Railway Operation Simulator  v2.4.2
A railway simulator for Windows
TrackUnit.cpp
Go to the documentation of this file.
1 // TrackUnit.cpp
2 /*
3  BEWARE OF COMMENTS in .cpp files: they were accurate when written but have
4  sometimes been overtaken by changes and not updated
5  Comments in .h files are believed to be accurate and up to date
6 
7  This is a source code file for "railway.exe", a railway operation
8  simulator, written originally in Borland C++ Builder 4 Professional with
9  later updates in Embarcadero C++Builder 10.2.
10  Copyright (C) 2010 Albert Ball [original development]
11 
12  This program is free software: you can redistribute it and/or modify
13  it under the terms of the GNU General Public License as published by
14  the Free Software Foundation, either version 3 of the License, or
15  (at your option) any later version.
16 
17  This program is distributed in the hope that it will be useful,
18  but WITHOUT ANY WARRANTY; without even the implied warranty of
19  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20  GNU General Public License for more details.
21 
22  You should have received a copy of the GNU General Public License
23  along with this program. If not, see <http://www.gnu.org/licenses/>.
24 */
25 // ---------------------------------------------------------------------------
26 #include <Classes.hpp>
27 #include <Controls.hpp>
28 #include <StdCtrls.hpp>
29 #include <Forms.hpp>
30 #include <Buttons.hpp>
31 #include <ExtCtrls.hpp>
32 #include <Menus.hpp>
33 #include <Dialogs.hpp>
34 #include <Graphics.hpp>
35 #include <ComCtrls.hpp>
36 #include <fstream>
37 #include <vector>
38 #include <vcl.h>
39 
40 #pragma hdrstop
41 
42 #include "TrackUnit.h"
43 #include "Utilities.h"
44 // #include "DisplayUnit.h" included in header file
45 #include "GraphicUnit.h"
46 #include "TextUnit.h"
47 #include "TrainUnit.h"
48 
49 #pragma package(smart_init)
50 // ---------------------------------------------------------------------------
51 
54 
55 // ---------------------------------------------------------------------------
56 
57 // FIXED TRACK :-
58 
59 // Constructor to build TrackPieces from array
60 
61 TFixedTrackPiece::TFixedTrackPiece(int SpeedTagVal, TTrackType TrackTypeVal, int LkVal[4], TConfiguration ConfigVal[4], Graphics::TBitmap* GraphicPtrVal,
62  Graphics::TBitmap* SmallGraphicPtrVal): SpeedTag(SpeedTagVal), TrackType(TrackTypeVal), GraphicPtr(GraphicPtrVal), SmallGraphicPtr(SmallGraphicPtrVal)
63 {
64  for(int x = 0; x < 4; x++)
65  {
66  Link[x] = LkVal[x];
67  Config[x] = ConfigVal[x];
68  }
69 // NamedLocationElements 76, 77, 78, 79, 96, 129, 130, 131, 145 & 146 (platforms, concourses, footcrossings & named non-station locations)
70  FixedNamedLocationElement = false; // underpasses (144 & 145 added at v2.3.1
71  if(SpeedTagVal == 76)
73  else if(SpeedTagVal == 77)
75  else if(SpeedTagVal == 78)
77  else if(SpeedTagVal == 79)
79  else if(SpeedTagVal == 96)
81  else if(SpeedTagVal == 129)
83  else if(SpeedTagVal == 130)
85  else if(SpeedTagVal == 131)
87  else if(SpeedTagVal == 145)
89  else if(SpeedTagVal == 146)
91 }
92 
93 // ---------------------------------------------------------------------------
94 
95 TFixedTrackPiece::TFixedTrackPiece(): SpeedTag(0), TrackType(Erase), GraphicPtr(RailGraphics->bmSolidBgnd), SmallGraphicPtr(RailGraphics->smSolidBgnd),
96  FixedNamedLocationElement(false) // default values
97 {
98  for(int x = 0; x < 4; x++)
99  {
100  Link[x] = -1; // -1 & NotSet are the markers for 'unused' respectively
101  Config[x] = NotSet;
102  }
103 }
104 
105 // ---------------------------------------------------------------------------
106 void TFixedTrackPiece::PlotFixedTrackElement(int Caller, int HLocInput, int VLocInput) const
107 {
108  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotFixedTrackElement," + AnsiString(HLocInput) + "," +
109  AnsiString(VLocInput));
110  Display->PlotOutput(33, HLocInput * 16, VLocInput * 16, GraphicPtr);
111  Utilities->CallLogPop(1331);
112 }
113 
114 // ---------------------------------------------------------------------------
115 
116 // VARIABLE TRACK :-
117 
118 // ---------------------------------------------------------------------------
119 
121 {
122  if((this->HLoc == RHElement.HLoc) && (this->VLoc == RHElement.VLoc) && (this->SpeedTag == RHElement.SpeedTag))
123  return true;
124  else
125  return false;
126 }
127 
128 // ---------------------------------------------------------------------------
129 
131 {
132  if((this->HLoc != RHElement.HLoc) || (this->VLoc != RHElement.VLoc) || (this->SpeedTag != RHElement.SpeedTag))
133  return true;
134  else
135  return false;
136 }
137 
138 // ---------------------------------------------------------------------------
139 
141  // 'Variable' in the sense that element might be striped or non-striped
142 {
143  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotVariableTrackElement");
144  Graphics::TBitmap *GraphicOutput = GraphicPtr;
145 
146  if(LocationName == "")
147  {
148  switch(SpeedTag)
149  {
150  case 76: // t platform
151  GraphicOutput = RailGraphics->gl76Striped;
152  break;
153 
154  case 77: // h platform
155  GraphicOutput = RailGraphics->bm77Striped;
156  break;
157 
158  case 78: // v platform
159  GraphicOutput = RailGraphics->bm78Striped;
160  break;
161 
162  case 79: // r platform
163  GraphicOutput = RailGraphics->gl79Striped;
164  break;
165 
166  case 96: // concourse
167  GraphicOutput = RailGraphics->ConcourseStriped;
168  break;
169 
170  case 129: // v footbridge
171  GraphicOutput = RailGraphics->gl129Striped;
172  break;
173 
174  case 130: // h footbridge
175  GraphicOutput = RailGraphics->gl130Striped;
176  break;
177 
178  case 131: // non-station named loc
179  GraphicOutput = RailGraphics->bmNameStriped;
180  break;
181 
182  case 145: // v underpass
183  GraphicOutput = RailGraphics->gl145Striped;
184  break;
185 
186  case 146: // h underpass
187  GraphicOutput = RailGraphics->gl146Striped;
188  break;
189 
190  default:
191  GraphicOutput = GraphicPtr;
192  break;
193  }
194  }
195  Disp->PlotOutput(34, HLoc * 16, VLoc * 16, GraphicOutput);
196  Utilities->CallLogPop(1332);
197 }
198 
199 // ---------------------------------------------------------------------------
200 
201 AnsiString TTrackElement::LogTrack(int Caller) const
202  // for debugging when passes as a call parameter
203 {
204  AnsiString LogString = "TrkEl:-," + AnsiString(ElementID) + "," + LocationName + "," + AnsiString(TrainIDOnElement) + "," +
205  AnsiString(TrainIDOnBridgeTrackPos01) + "," + AnsiString(TrainIDOnBridgeTrackPos23) + ",EndTrkEl,";
206 
207  return LogString;
208 }
209 
210 // ---------------------------------------------------------------------------
211 
212 bool TMapComp:: operator()(const THVPair& lower, const THVPair& higher) const // HLoc VLoc
213 {
214  if(lower.second < higher.second)
215  {
216  return true;
217  }
218  else if(lower.second > higher.second)
219  {
220  return false;
221  }
222  else if(lower.second == higher.second)
223  {
224  if(lower.first < higher.first)
225  {
226  return true;
227  }
228  }
229  return false;
230 }
231 
232 // ---------------------------------------------------------------------------
233 // PrefDirElement Functions
234 // ---------------------------------------------------------------------------
235 
236 TPrefDirElement::TPrefDirElement(TTrackElement ElementIn, int ELinkIn, int ELinkPosIn, int XLinkIn, int XLinkPosIn, int TrackVectorPositionIn)
237  : TTrackElement(ElementIn), ELink(ELinkIn), ELinkPos(ELinkPosIn), XLink(XLinkIn), XLinkPos(XLinkPosIn), TrackVectorPosition(TrackVectorPositionIn),
238  CheckCount(9), IsARoute(false), AutoSignals(false), ConsecSignals(false)
239 {
240  if(!EntryExitNumber())
241  {
242  throw Exception("EXNumber failure in TPrefDirElement constructor");
243  }
246 }
247 
248 // ---------------------------------------------------------------------------
249 
250 AnsiString TPrefDirElement::LogPrefDir() const
251  // for debugging when passed as a call parameter
252 {
253  AnsiString LogString = "PthEl:-," + AnsiString(ELink) + "," + AnsiString(ELinkPos) + "," + AnsiString(XLink) + "," + AnsiString(XLinkPos) + "," +
254  AnsiString(EXNumber) + "," + AnsiString(TrackVectorPosition) + "," + AnsiString((short)AutoSignals) + "," + AnsiString((short)ConsecSignals) +
255  ",ElementID," + AnsiString(ElementID) + "," + LocationName + "," + AnsiString(TrainIDOnElement) + "," + AnsiString(TrainIDOnBridgeTrackPos01) + "," +
256  AnsiString(TrainIDOnBridgeTrackPos23);
257 
258 // Track->TrackElementAt(73, TrackVectorPosition).LogTrack(12);
259  return LogString;
260 }
261 
262 // ---------------------------------------------------------------------------
263 
264 bool TPrefDirElement::EntryExitNumber() // true for valid number
265 /*
266  Computes a number corresponding to ELink & Xlink if set, or to the entry and exit link values for the track
267  at Link[0] and Link[1], or, if ELink or XLink not set, and a complex (4-entry) element, return false for error message.
268  This should be OK because only elements for which ELink & XLink not set are PrefDir/route start elements and leading points
269  as temporary end of PrefDir, and in both cases this function is not called as the direction is not displayed for these elements.
270  Uses simple links between any 2 entry & exit points for use in displaying PrefDir or route graphics, or original graphic during
271  route flashing. Should only be called when ELink & XLink set, or when ELinkPos & XLinkPos set deliberately from a
272  TTrackElement during route setting functions. If a bridge then an additional check is made in case the graphic needed
273  corresponds to an undebridge, i.e a gap needed between entry and exit. In this case the EXNumber is increased by
274  16 so as to be unique. Returns true if valid and sets EXNumber to the selected value.
275 */
276 
277 {
278  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",EntryExitNumber");
279  int EXArray[16][2] =
280  {{4, 6}, {2, 8}, // horizontal & vertical
281  {2, 4}, {6, 2}, {8, 6}, {4, 8}, // sharp curves
282  {1, 6}, {3, 8}, {9, 4}, {7, 2}, {1, 8}, {3, 4}, {9, 2}, {7, 6}, // loose curves
283  {1, 9}, {3, 7}}; // forward & reverse diagonals
284 
285  int EXNum = -1;
286  int Entry, Exit;
287 
288  if(ELink > -1)
289  Entry = ELink; // pick up simple elements even if ELink &/or XLink not set, as no ambiguity
290  else if(Link[2] == -1)
291  Entry = Link[0];
292  else
293  {
294  Utilities->CallLogPop(122);
295  return false;
296  }
297  if(XLink > -1)
298  Exit = XLink;
299  else if(Link[2] == -1)
300  Exit = Link[1];
301  else
302  {
303  Utilities->CallLogPop(123);
304  return false;
305  }
306 
307  for(int x = 0; x < 16; x++)
308  {
309  if((Entry == EXArray[x][0]) && (Exit == EXArray[x][1]) || (Entry == EXArray[x][1]) && (Exit == EXArray[x][0]))
310  {
311  EXNum = x;
312  }
313  }
314  if(EXNum == -1)
315  {
316  Utilities->CallLogPop(124);
317  return false;
318  }
319 
320  int BrNum = -1;
321 
322 /* The order for bridge entries & exits is as below. Note that there are 3 of each type,
323  the graphic for each of which is different because of the shape of the overbridge. The basic
324  entry/exit value is computed above, and this used to select only from elements with that entry/exit
325  value that is an underbridge, i.e overbridges ignored as the normal graphic is OK for them.
326  int BrEXArray[24][2] = {
327  {4,6},{2,8},{1,9},{3,7},
328  {1,9},{3,7},{1,9},{3,7},
329  {2,8},{4,6},{2,8},{4,6}
330 */
331 
332  if(TrackType == Bridge)
333  {
334  if(EXNum == 1)
335  {
336  if(SpeedTag == 49)
337  BrNum = 1 + 16;
338  else if(SpeedTag == 54)
339  BrNum = 8 + 16;
340  else if(SpeedTag == 55)
341  BrNum = 10 + 16;
342  }
343  else if(EXNum == 0)
344  {
345  if(SpeedTag == 48)
346  BrNum = 0 + 16;
347  else if(SpeedTag == 58)
348  BrNum = 11 + 16;
349  else if(SpeedTag == 59)
350  BrNum = 9 + 16;
351  }
352  else if(EXNum == 14)
353  {
354  if(SpeedTag == 50)
355  BrNum = 2 + 16;
356  else if(SpeedTag == 52)
357  BrNum = 4 + 16;
358  else if(SpeedTag == 57)
359  BrNum = 6 + 16;
360  }
361  else if(EXNum == 15)
362  {
363  if(SpeedTag == 51)
364  BrNum = 3 + 16;
365  else if(SpeedTag == 53)
366  BrNum = 7 + 16;
367  else if(SpeedTag == 56)
368  BrNum = 5 + 16;
369  }
370  }
371  if(BrNum == -1)
372  EXNumber = EXNum;
373  else
374  EXNumber = BrNum;
375  Utilities->CallLogPop(125);
376  return true;
377 }
378 
379 // ---------------------------------------------------------------------------
380 
382 /*
383  This is the basic track graphic for use in plotting the original graphic during route flashing.
384  Enter with all set apart from EXGraphic & EntryDirectionGraphic
385 */
386 {
387  if(SpeedTag == 64)
388  return RailGraphics->LinkGraphicsPtr[16]; // intercept diagonal buffers
389 
390  if(SpeedTag == 65)
391  return RailGraphics->LinkGraphicsPtr[17];
392 
393  if(SpeedTag == 66)
394  return RailGraphics->LinkGraphicsPtr[18];
395 
396  if(SpeedTag == 67)
397  return RailGraphics->LinkGraphicsPtr[19];
398 
399  if(SpeedTag == 80)
400  return RailGraphics->LinkGraphicsPtr[20]; // intercept continuations
401 
402  if(SpeedTag == 81)
403  return RailGraphics->LinkGraphicsPtr[21];
404 
405  if(SpeedTag == 82)
406  return RailGraphics->LinkGraphicsPtr[22];
407 
408  if(SpeedTag == 83)
409  return RailGraphics->LinkGraphicsPtr[23];
410 
411  if(SpeedTag == 84)
412  return RailGraphics->LinkGraphicsPtr[24];
413 
414  if(SpeedTag == 85)
415  return RailGraphics->LinkGraphicsPtr[25];
416 
417  if(SpeedTag == 86)
418  return RailGraphics->LinkGraphicsPtr[26];
419 
420  if(SpeedTag == 87)
421  return RailGraphics->LinkGraphicsPtr[27];
422 
423  if(SpeedTag == 129)
424  return RailGraphics->LinkGraphicsPtr[28]; // intercept under footbridges
425 
426  if(SpeedTag == 130)
427  return RailGraphics->LinkGraphicsPtr[29];
428 
429  if(XLinkPos == -1) // not set, could be first element or last element = leading point
430  {
431 // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or
432 // Points & don't want to display these)
433  if(Link[2] != -1)
434  return 0; // i.e. complex element, don't display
435  else
436  {
437  if(!EntryExitNumber())
438  {
439  throw Exception("Error in EntryExitNumber 4");
440  }
441  else
442  {
444  }
445  }
446  }
447  if(EXNumber > 15) // underbridge
448  {
450  }
451  else
452  {
454  }
455 }
456 
457 // ---------------------------------------------------------------------------
458 
460 /*
461  As above but for PrefDir graphics.
462 */
463 {
464  if(SpeedTag == 64)
465  return RailGraphics->LinkPrefDirGraphicsPtr[16]; // intercept diagonal buffers
466 
467  if(SpeedTag == 65)
469 
470  if(SpeedTag == 66)
472 
473  if(SpeedTag == 67)
475 
476  if(SpeedTag == 80)
477  return RailGraphics->LinkPrefDirGraphicsPtr[20]; // intercept continuations
478 
479  if(SpeedTag == 81)
481 
482  if(SpeedTag == 82)
484 
485  if(SpeedTag == 83)
487 
488  if(SpeedTag == 84)
490 
491  if(SpeedTag == 85)
493 
494  if(SpeedTag == 86)
496 
497  if(SpeedTag == 87)
499 
500  if(SpeedTag == 129)
501  return RailGraphics->LinkPrefDirGraphicsPtr[28]; // intercept under footbridges
502 
503  if(SpeedTag == 130)
505 
506  if(XLinkPos == -1) // not set, could be first element or last element = leading point
507  {
508 // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
509  if(Link[2] != -1)
510  return 0; // i.e. complex element, don't display
511  else
512  {
513  if(!EntryExitNumber())
514  {
515  throw Exception("Error in EntryExitNumber 5");
516  }
517  else
519  }
520  }
521  if(EXNumber > 15) // underbridge
522  {
524  }
525  else
527 }
528 
529 // ---------------------------------------------------------------------------
530 
531 Graphics::TBitmap *TPrefDirElement::GetRouteGraphicPtr(bool AutoSigsFlag, bool ConsecSignalsRoute)
532 /*
533  As above but for route graphics.
534 */
535 {
536  if(!AutoSigsFlag && !ConsecSignalsRoute)
537  {
538  if(SpeedTag == 64)
539  return RailGraphics->LinkNonSigRouteGraphicsPtr[16]; // intercept diagonal buffers
540 
541  if(SpeedTag == 65)
543 
544  if(SpeedTag == 66)
546 
547  if(SpeedTag == 67)
549 
550  if(SpeedTag == 80)
551  return RailGraphics->LinkNonSigRouteGraphicsPtr[20]; // intercept continuations
552 
553  if(SpeedTag == 81)
555 
556  if(SpeedTag == 82)
558 
559  if(SpeedTag == 83)
561 
562  if(SpeedTag == 84)
564 
565  if(SpeedTag == 85)
567 
568  if(SpeedTag == 86)
570 
571  if(SpeedTag == 87)
573 
574  if(SpeedTag == 129)
575  return RailGraphics->LinkNonSigRouteGraphicsPtr[28]; // intercept under footbridges
576 
577  if(SpeedTag == 130)
579 
580  if(XLinkPos == -1) // not set, could be first element or last element = leading point
581  {
582  // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
583  if(Link[2] != -1)
584  return 0; // i.e. complex element, don't display
585  else
586  {
587  if(!EntryExitNumber())
588  {
589  throw Exception("Error in EntryExitNumber 6");
590  }
591  else
593  }
594  }
595  if(EXNumber > 15) // underbridge
596  {
598  }
599  else
601  }
602 
603  else if(!AutoSigsFlag && ConsecSignalsRoute)
604  {
605  if(SpeedTag == 64)
606  return RailGraphics->LinkSigRouteGraphicsPtr[16]; // intercept diagonal buffers
607 
608  if(SpeedTag == 65)
610 
611  if(SpeedTag == 66)
613 
614  if(SpeedTag == 67)
616 
617  if(SpeedTag == 80)
618  return RailGraphics->LinkSigRouteGraphicsPtr[20]; // intercept continuations
619 
620  if(SpeedTag == 81)
622 
623  if(SpeedTag == 82)
625 
626  if(SpeedTag == 83)
628 
629  if(SpeedTag == 84)
631 
632  if(SpeedTag == 85)
634 
635  if(SpeedTag == 86)
637 
638  if(SpeedTag == 87)
640 
641  if(SpeedTag == 129)
642  return RailGraphics->LinkSigRouteGraphicsPtr[28]; // intercept under footbridges
643 
644  if(SpeedTag == 130)
646 
647  if(XLinkPos == -1) // not set, could be first element or last element = leading point
648  {
649  // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
650  if(Link[2] != -1)
651  return 0; // i.e. complex element, don't display
652  else
653  {
654  if(!EntryExitNumber())
655  {
656  throw Exception("Error in EntryExitNumber 10");
657  }
658  else
660  }
661  }
662  if(EXNumber > 15) // underbridge
663  {
665  }
666  else
668  }
669 
670  else
671  {
672  if(SpeedTag == 64)
673  return RailGraphics->LinkRouteAutoSigsGraphicsPtr[16]; // intercept diagonal buffers
674 
675  if(SpeedTag == 65)
677 
678  if(SpeedTag == 66)
680 
681  if(SpeedTag == 67)
683 
684  if(SpeedTag == 80)
685  return RailGraphics->LinkRouteAutoSigsGraphicsPtr[20]; // intercept continuations
686 
687  if(SpeedTag == 81)
689 
690  if(SpeedTag == 82)
692 
693  if(SpeedTag == 83)
695 
696  if(SpeedTag == 84)
698 
699  if(SpeedTag == 85)
701 
702  if(SpeedTag == 86)
704 
705  if(SpeedTag == 87)
707 
708  if(SpeedTag == 129)
709  return RailGraphics->LinkRouteAutoSigsGraphicsPtr[28]; // intercept under footbridges
710 
711  if(SpeedTag == 130)
713 
714  if(XLinkPos == -1) // not set, could be first element or last element = leading point
715  {
716  // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
717  if(Link[2] != -1)
718  return 0; // i.e. complex element, don't display
719  else
720  {
721  if(!EntryExitNumber())
722  {
723  throw Exception("Error in EntryExitNumber 11");
724  }
725  else
727  }
728  }
729  if(EXNumber > 15) // underbridge
730  {
732  }
733  else
735  }
736 }
737 
738 // ---------------------------------------------------------------------------
739 
741 /*
742  As above but for route flashing graphics. (Disused - now combined with above)
743 */
744 {
745  if(SpeedTag == 64)
746  return RailGraphics->LinkRouteAutoSigsGraphicsPtr[16]; // intercept diagonal buffers
747 
748  if(SpeedTag == 65)
750 
751  if(SpeedTag == 66)
753 
754  if(SpeedTag == 67)
756 
757  if(SpeedTag == 80)
758  return RailGraphics->LinkRouteAutoSigsGraphicsPtr[20]; // intercept continuations
759 
760  if(SpeedTag == 81)
762 
763  if(SpeedTag == 82)
765 
766  if(SpeedTag == 83)
768 
769  if(SpeedTag == 84)
771 
772  if(SpeedTag == 85)
774 
775  if(SpeedTag == 86)
777 
778  if(SpeedTag == 87)
780 
781  if(SpeedTag == 129)
782  return RailGraphics->LinkRouteAutoSigsGraphicsPtr[28]; // intercept under footbridges
783 
784  if(SpeedTag == 130)
786 
787  if(XLinkPos == -1) // not set, could be first element or last element = leading point
788  {
789 // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
790  if(Link[2] != -1)
791  return 0; // i.e. complex element, don't display
792  else
793  {
794  if(!EntryExitNumber())
795  {
796  throw Exception("Error in EntryExitNumber 7");
797  }
798  else
800  }
801  }
802  if(EXNumber > 15) // underbridge
803  {
805  }
806  else
808 }
809 
810 // ---------------------------------------------------------------------------
811 
813 /*
814  Get PrefDir direction graphic. Enter with all set apart from EXGraphic & EntryDirectionGraphic
815 */
816 {
817  if((ELink > 0) && (ELink < 10) && (ELink != 5))
819  else
820  {
821  throw Exception("Error in EntryExitNumber 8");
822  }
823 }
824 
825 // ---------------------------------------------------------------------------
826 
827 Graphics::TBitmap *TPrefDirElement::GetDirectionRouteGraphicPtr(bool AutoSigsFlag, bool ConsecSignalsRoute) const
828 /*
829  Get route direction graphic. Enter with all set apart from EXGraphic & EntryDirectionGraphic
830 */
831 {
832  if((ELink > 0) && (ELink < 10) && (ELink != 5))
833  {
834  if(!AutoSigsFlag && !ConsecSignalsRoute)
836  else if(!AutoSigsFlag && ConsecSignalsRoute)
838  else
840  }
841  else
842  {
843  throw Exception("Error in EntryExitNumber 9");
844  }
845 }
846 
847 // ---------------------------------------------------------------------------
848 
850 /*
851  Set == operator when TrackVectorPosition, ELink & XLink all same
852 */
853 {
854  if((this->TrackVectorPosition == RHElement.TrackVectorPosition) && (this->ELink == RHElement.ELink) && (this->XLink == RHElement.XLink))
855  return true;
856  else
857  return false;
858 }
859 
860 // ---------------------------------------------------------------------------
861 
863 /*
864  Set != operator when any of TrackVectorPosition, ELink or XLink different
865 */
866 {
867  if((this->TrackVectorPosition == RHElement.TrackVectorPosition) && (this->ELink == RHElement.ELink) && (this->XLink == RHElement.XLink))
868  return false;
869  else
870  return true;
871 }
872 
873 // ---------------------------------------------------------------------------
874 // Track functions
875 // ---------------------------------------------------------------------------
876 
877 // ---------------------------------------------------------------------------
878 
879 TTrack::TActiveLevelCrossing::TActiveLevelCrossing()
880 {
881  ConsecSignals = false;
882  TrainPassed = false;
883  BarrierState = Up;
884  ChangeDuration = 0.0;
886  HLoc = 0;
887  VLoc = 0;
888  StartTime = TDateTime(0);
889 }
890 
891 // ---------------------------------------------------------------------------
892 
894 {
895 // CurrentSpeedButtonTag = 0; //not assigned yet
896 
897  HLocMin = 2000000000;
898  VLocMin = 2000000000;
899  HLocMax = -2000000000;
900  VLocMax = -2000000000;
901  SkipLocationNameMultiMapCheck = false; // new at v2.2.0, false is default value
902  CopyFlag = false; // only true for copying, so names aren't copied
903 
904  AnsiString NL = '\n';
905 
906  RouteFailMessage = "Unable to set a route: it may be unreachable; " + NL +
907  "reachable but with too many different directions leading away from the start point - set some points on the route required; " + NL +
908  "blocked by a train, another route or a changing level crossing; " + NL +
909  "or invalid - possibly due to a preferred direction mismatch or a missed signal in a green or blue route.";
910 
915 
916  int InternalLinkCheckArray[9][2] =
917  {{1, 9}, {4, 6}, {7, 3}, {2, 8}, {0, 0}, {8, 2}, {3, 7}, {6, 4}, {9, 1}};
918 
919 /* array of valid link values for 'old' location and 'new' location, where
920  array number = (((Hnew - Hold)+1)*3) + ((Vnew - Vold)+1) */
921 
922  for(int x = 0; x < 9; x++)
923  for(int y = 0; y < 2; y++)
924  LinkCheckArray[x][y] = InternalLinkCheckArray[x][y];
925 
926 // Platform and default track element values
927  TopPlatAllowed << 1 << 9 << 10 << 30 << 31 << 60 << 61 << 68 << 69 << 77 << 125 << 126 << 129 << 145;
928 // top & bot sigs, straights, straight points, buffers, signal, vert footcrossing, bot plat
929  BotPlatAllowed << 1 << 7 << 8 << 28 << 29 << 60 << 61 << 68 << 69 << 76 << 125 << 126 << 129 << 145;
930  LeftPlatAllowed << 2 << 12 << 14 << 33 << 35 << 62 << 63 << 70 << 71 << 79 << 127 << 128 << 130 << 146;
931  RightPlatAllowed << 2 << 11 << 13 << 32 << 34 << 62 << 63 << 70 << 71 << 78 << 127 << 128 << 130 << 146;
932  NameAllowed << 1 << 2 << 3 << 4 << 5 << 6 << 20 << 21 << 22 << 23 << 24 << 25 << 26 << 27 // disallow diagonals, points, signals, crossovers, bridges, gaps,
933  << 60 << 61 << 62 << 63 << 80 << 81 << 82 << 83 << 125 << 126 << 127 << 128; // diag continuations, diag buffers, footcrossings (diagonals may be OK
934  // but as can't link diagonal locations would need solid blocks to allow linkage & that would look untidy except for single
935  // elements, & can always use straights so leave out.)
936  LevelCrossingAllowed << 1 << 2; // only allow on straight tracks without direction markers
937 // Note platforms not allowed at continuations, but named non-station locations OK, though not allowed in timetables
938 
939  int HVArray[10][2] =
940  {{0, 0}, {-1, -1}, {0, -1}, {1, -1}, {-1, 0}, {0, 0}, {1, 0}, {-1, 1}, {0, 1}, {1, 1}};
941 
942  for(int x = 0; x < 10; x++)
943  for(int y = 0; y < 2; y++)
944  LinkHVArray[x][y] = HVArray[x][y];
945  TrackFinished = false;
946 // DistancesSet = false;
947 
948  TSigElement TempSigTable[40] = // original four aspect
949  {{68, 0, RailGraphics->gl68}, {69, 0, RailGraphics->gl69}, {70, 0, RailGraphics->gl70}, {71, 0, RailGraphics->gl71}, {72, 0, RailGraphics->gl72},
950  {73, 0, RailGraphics->bm73}, {74, 0, RailGraphics->bm74}, {75, 0, RailGraphics->gl75},
951 
954 
957 
958  {68, 3, RailGraphics->bm68green}, {69, 3, RailGraphics->bm69green}, {70, 3, RailGraphics->bm70green}, {71, 3, RailGraphics->bm71green},
959  {72, 3, RailGraphics->bm72green}, {73, 3, RailGraphics->bm73green}, {74, 3, RailGraphics->bm74green}, {75, 3, RailGraphics->bm75green},
960 
961  {68, 4, RailGraphics->gl68}, {69, 4, RailGraphics->gl69}, // Attr 4 disused but leave in case re-instate
962  {70, 4, RailGraphics->gl70}, {71, 4, RailGraphics->gl71}, {72, 4, RailGraphics->gl72}, {73, 4, RailGraphics->bm73}, {74, 4, RailGraphics->bm74},
963  {75, 4, RailGraphics->gl75}};
964 
965  for(int x = 0; x < 40; x++)
966  {
967  SigTable[x] = TempSigTable[x];
968  }
969 
970  TSigElement TempSigTableThreeAspect[40] =
971  {{68, 0, RailGraphics->gl68}, {69, 0, RailGraphics->gl69}, {70, 0, RailGraphics->gl70}, {71, 0, RailGraphics->gl71}, {72, 0, RailGraphics->gl72},
972  {73, 0, RailGraphics->bm73}, {74, 0, RailGraphics->bm74}, {75, 0, RailGraphics->gl75},
973 
976 
977  {68, 2, RailGraphics->bm68green}, {69, 2, RailGraphics->bm69green}, {70, 2, RailGraphics->bm70green}, {71, 2, RailGraphics->bm71green},
978  {72, 2, RailGraphics->bm72green}, {73, 2, RailGraphics->bm73green}, {74, 2, RailGraphics->bm74green}, {75, 2, RailGraphics->bm75green},
979 
980  {68, 3, RailGraphics->bm68green}, {69, 3, RailGraphics->bm69green}, {70, 3, RailGraphics->bm70green}, {71, 3, RailGraphics->bm71green},
981  {72, 3, RailGraphics->bm72green}, {73, 3, RailGraphics->bm73green}, {74, 3, RailGraphics->bm74green}, {75, 3, RailGraphics->bm75green},
982 
983  {68, 4, RailGraphics->gl68}, {69, 4, RailGraphics->gl69}, // Attr 4 disused but leave in case re-instate
984  {70, 4, RailGraphics->gl70}, {71, 4, RailGraphics->gl71}, {72, 4, RailGraphics->gl72}, {73, 4, RailGraphics->bm73}, {74, 4, RailGraphics->bm74},
985  {75, 4, RailGraphics->gl75}};
986 
987  for(int x = 0; x < 40; x++)
988  {
989  SigTableThreeAspect[x] = TempSigTableThreeAspect[x];
990  }
991 
992  TSigElement TempSigTableTwoAspect[40] =
993  {{68, 0, RailGraphics->gl68}, {69, 0, RailGraphics->gl69}, {70, 0, RailGraphics->gl70}, {71, 0, RailGraphics->gl71}, {72, 0, RailGraphics->gl72},
994  {73, 0, RailGraphics->bm73}, {74, 0, RailGraphics->bm74}, {75, 0, RailGraphics->gl75},
995 
996  {68, 1, RailGraphics->bm68green}, {69, 1, RailGraphics->bm69green}, {70, 1, RailGraphics->bm70green}, {71, 1, RailGraphics->bm71green},
997  {72, 1, RailGraphics->bm72green}, {73, 1, RailGraphics->bm73green}, {74, 1, RailGraphics->bm74green}, {75, 1, RailGraphics->bm75green},
998 
999  {68, 2, RailGraphics->bm68green}, {69, 2, RailGraphics->bm69green}, {70, 2, RailGraphics->bm70green}, {71, 2, RailGraphics->bm71green},
1000  {72, 2, RailGraphics->bm72green}, {73, 2, RailGraphics->bm73green}, {74, 2, RailGraphics->bm74green}, {75, 2, RailGraphics->bm75green},
1001 
1002  {68, 3, RailGraphics->bm68green}, {69, 3, RailGraphics->bm69green}, {70, 3, RailGraphics->bm70green}, {71, 3, RailGraphics->bm71green},
1003  {72, 3, RailGraphics->bm72green}, {73, 3, RailGraphics->bm73green}, {74, 3, RailGraphics->bm74green}, {75, 3, RailGraphics->bm75green},
1004 
1005  {68, 4, RailGraphics->gl68}, {69, 4, RailGraphics->gl69}, // Attr 4 disused but leave in case re-instate
1006  {70, 4, RailGraphics->gl70}, {71, 4, RailGraphics->gl71}, {72, 4, RailGraphics->gl72}, {73, 4, RailGraphics->bm73}, {74, 4, RailGraphics->bm74},
1007  {75, 4, RailGraphics->gl75}};
1008 
1009  for(int x = 0; x < 40; x++)
1010  {
1011  SigTableTwoAspect[x] = TempSigTableTwoAspect[x];
1012  }
1013 
1014  TSigElement TempSigTableGroundSignal[40] =
1018 
1022 
1026 
1030 
1031  {68, 4, RailGraphics->bm68grounddblred}, {69, 4, RailGraphics->bm69grounddblred}, // Attr 4 disused but leave in case re-instate
1034 
1035  for(int x = 0; x < 40; x++)
1036  {
1037  SigTableGroundSignal[x] = TempSigTableGroundSignal[x];
1038  }
1039 
1040 /*
1041  Named Location Arrays: Set out the adjacent positions and tracktypes that are accepted as valid connections for
1042  a single location. These are as follows:-
1043  Directly Adjacent = up, down, left or right - NOT diagonal.
1044  There are two separate groups, platforms, concourses & footcrossings (providing the crossing part touches or overlaps the other relevant
1045  named location) all link with each other providing directly adjacent, but not to NamedNonStationLocations.
1046  NamedNonStationLocation link to other NamedNonStationLocations providing directly adjacent, but not to anything else.
1047 
1048  //t 76
1049  //b 77
1050  //l 78
1051  //r 79
1052  //c 96
1053  //v fb 129
1054  //h fb 130
1055  //v underpass 145
1056  //h underpass 146
1057  //n 131
1058 */
1059 
1060  int Tag76[25][3] =
1061  {{-1, 0, 96}, // c top plat
1062  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1063  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {-1, 0, 77}, // b
1064  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {0, 0, 77}, {-1, 0, 78}, // l
1065  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {-1, 0, 79}, // r
1066  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {0, -1, 129}, // v fb
1067  {0, 0, 129}, {0, -1, 145}, // v up
1068  {0, 0, 145}};
1069 
1070  for(int x = 0; x < 25; x++)
1071  for(int y = 0; y < 3; y++)
1072  Tag76Array[x][y] = Tag76[x][y];
1073 
1074  int Tag77[25][3] =
1075  {{-1, 0, 96}, // c bot plat
1076  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1077  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {0, 0, 76}, {-1, 0, 77}, // b
1078  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {-1, 0, 78}, // l
1079  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {-1, 0, 79}, // r
1080  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {0, 1, 129}, // v fb
1081  {0, 0, 129}, {0, 1, 145}, // v up
1082  {0, 0, 145}};
1083 
1084  for(int x = 0; x < 25; x++)
1085  for(int y = 0; y < 3; y++)
1086  Tag77Array[x][y] = Tag77[x][y];
1087 
1088  int Tag78[25][3] =
1089  {{-1, 0, 96}, // c left plat
1090  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1091  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {-1, 0, 77}, // b
1092  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {-1, 0, 78}, // l
1093  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {-1, 0, 79}, // r
1094  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {0, 0, 79}, {-1, 0, 130}, // h fb
1095  {0, 0, 130}, {-1, 0, 146}, // h up
1096  {0, 0, 146}};
1097 
1098  for(int x = 0; x < 25; x++)
1099  for(int y = 0; y < 3; y++)
1100  Tag78Array[x][y] = Tag78[x][y];
1101 
1102  int Tag79[25][3] =
1103  {{-1, 0, 96}, // c right plat
1104  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1105  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {-1, 0, 77}, // b
1106  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {-1, 0, 78}, // l
1107  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {0, 0, 78}, {-1, 0, 79}, // r
1108  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {1, 0, 130}, // h fb
1109  {0, 0, 130}, {1, 0, 146}, // h up
1110  {0, 0, 146}};
1111 
1112  for(int x = 0; x < 25; x++)
1113  for(int y = 0; y < 3; y++)
1114  Tag79Array[x][y] = Tag79[x][y];
1115 
1116  int Tag96[28][3] =
1117  {{-1, 0, 96}, // c //concourse
1118  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1119  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {-1, 0, 77}, // b
1120  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {-1, 0, 78}, // l
1121  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {-1, 0, 79}, // r
1122  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {0, 1, 129}, // v fb
1123  {0, -1, 129}, {1, 0, 130}, // h fb
1124  {-1, 0, 130}, {0, 1, 145}, // v up
1125  {0, -1, 145}, {1, 0, 146}, // h up
1126  {-1, 0, 146}};
1127 
1128  for(int x = 0; x < 28; x++)
1129  for(int y = 0; y < 3; y++)
1130  Tag96Array[x][y] = Tag96[x][y];
1131 
1132  int Tag129[8][3] = // vert fb
1133  {{0, -1, 96}, // c
1134  {0, -1, 77}, // b
1135  {0, -1, 129}, // v fb
1136 
1137  {0, 1, 96}, // c
1138  {0, 1, 76}, // t
1139  {0, 1, 129}, // v fb
1140 
1141  {0, 0, 76}, // t
1142  {0, 0, 77}}; // b
1143 
1144  for(int x = 0; x < 8; x++)
1145  for(int y = 0; y < 3; y++)
1146  Tag129Array[x][y] = Tag129[x][y];
1147 
1148  int Tag145[8][3] = // vert up
1149  {{0, -1, 96}, // c
1150  {0, -1, 77}, // b
1151  {0, -1, 145}, // v fb
1152 
1153  {0, 1, 96}, // c
1154  {0, 1, 76}, // t
1155  {0, 1, 145}, // v fb
1156 
1157  {0, 0, 76}, // t
1158  {0, 0, 77}}; // b
1159 
1160  for(int x = 0; x < 8; x++)
1161  for(int y = 0; y < 3; y++)
1162  Tag145Array[x][y] = Tag145[x][y];
1163 
1164  int Tag130[8][3] = // hor fb
1165  {{-1, 0, 96}, // c
1166  {-1, 0, 79}, // r
1167  {-1, 0, 130}, // h fb
1168 
1169  {1, 0, 96}, // c
1170  {1, 0, 78}, // l
1171  {1, 0, 130}, // h fb
1172 
1173  {0, 0, 78}, // l
1174  {0, 0, 79}}; // r
1175 
1176  for(int x = 0; x < 8; x++)
1177  for(int y = 0; y < 3; y++)
1178  Tag130Array[x][y] = Tag130[x][y];
1179 
1180  int Tag146[8][3] = // hor up
1181  {{-1, 0, 96}, // c
1182  {-1, 0, 79}, // r
1183  {-1, 0, 146}, // h fb
1184 
1185  {1, 0, 96}, // c
1186  {1, 0, 78}, // l
1187  {1, 0, 146}, // h fb
1188 
1189  {0, 0, 78}, // l
1190  {0, 0, 79}}; // r
1191 
1192  for(int x = 0; x < 8; x++)
1193  for(int y = 0; y < 3; y++)
1194  Tag146Array[x][y] = Tag146[x][y];
1195 
1196  int Tag131[4][3] =
1197  {{-1, 0, 131}, // n
1198  {1, 0, 131}, {0, -1, 131}, {0, 1, 131}};
1199 
1200  for(int x = 0; x < 4; x++)
1201  for(int y = 0; y < 3; y++)
1202  Tag131Array[x][y] = Tag131[x][y];
1203 
1204  int InternalFlipArray[FirstUnusedSpeedTagNumber] =
1205  {0, 1, 2, 5, 6, 3, 4, 9, 10, 7, 8, 13, 14, 11, 12, 15, 16, 17, 19, 18, 22, 23, 20, 21, 26, 27, 24, 25, 30, 31, 28, 29, 34, 35, 32, 33, 38, 39, 36, 37, 42,
1206  43, 40, 41, 45, 44, 47, 46, 48, 49, 51, 50, 53, 52, 55, 54, 57, 56, 59, 58, 60, 61, 63, 62, 66, 67, 64, 65, 68, 69, 71, 70, 74, 75, 72, 73, 77, 76, 78,
1207  79, 80, 81, 83, 82, 86, 87, 84, 85, 88, 89, 91, 90, 94, 95, 92, 93, 96, 99, 100, 97, 98, 103, 104, 101, 102, 106, 105, 109, 110, 107, 108, 113, 114,
1208  111, 112, 117, 118, 115, 116, 119, 120, 121, 123, 122, 124, 125, 126, 128, 127, 129, 130, 131, 134, 133, 132, 135, 139, 138, 137, 136, 143, 142, 141,
1209  140, 144, 145, 146};
1210 
1211  int InternalMirrorArray[FirstUnusedSpeedTagNumber] =
1212  {0, 1, 2, 4, 3, 6, 5, 8, 7, 10, 9, 12, 11, 14, 13, 15, 16, 17, 19, 18, 21, 20, 23, 22, 25, 24, 27, 26, 29, 28, 31, 30, 33, 32, 35, 34, 37, 36, 39, 38, 41,
1213  40, 43, 42, 45, 44, 47, 46, 48, 49, 51, 50, 53, 52, 55, 54, 57, 56, 59, 58, 61, 60, 62, 63, 65, 64, 67, 66, 69, 68, 70, 71, 73, 72, 75, 74, 76, 77, 79,
1214  78, 81, 80, 82, 83, 85, 84, 87, 86, 89, 88, 90, 91, 93, 92, 95, 94, 96, 98, 97, 100, 99, 102, 101, 104, 103, 106, 105, 108, 107, 110, 109, 112, 111,
1215  114, 113, 116, 115, 118, 117, 119, 120, 124, 122, 123, 121, 126, 125, 127, 128, 129, 130, 131, 132, 135, 134, 133, 137, 136, 139, 138, 142, 143, 140,
1216  141, 144, 145, 146};
1217 
1218  int InternalRotRightArray[FirstUnusedSpeedTagNumber] =
1219  {0, 2, 1, 4, 6, 3, 5, 14, 12, 13, 11, 7, 9, 8, 10, 15, 16, 17, 19, 18, 25, 27, 24, 26, 21, 23, 20, 22, 35, 33, 34, 32, 28, 30, 29, 31, 41, 43, 40, 42, 37,
1220  39, 36, 38, 46, 47, 44, 45, 49, 48, 51, 50, 56, 57, 58, 59, 52, 53, 54, 55, 63, 62, 60, 61, 65, 67, 64, 66, 71, 70, 68, 69, 73, 75, 72, 74, 79, 78, 76,
1221  77, 83, 82, 80, 81, 85, 87, 84, 86, 91, 90, 88, 89, 93, 95, 92, 94, 96, 102, 104, 101, 103, 98, 100, 97, 99, 106, 105, 108, 110, 107, 109, 116, 118,
1222  115, 117, 112, 114, 111, 113, 120, 119, 122, 124, 121, 123, 127, 128, 126, 125, 130, 129, 131, 133, 134, 135, 132, 137, 138, 139, 136, 143, 142, 140,
1223  141, 144, 146, 145};
1224 
1225  int InternalRotLeftArray[FirstUnusedSpeedTagNumber] =
1226  {0, 2, 1, 5, 3, 6, 4, 11, 13, 12, 14, 10, 8, 9, 7, 15, 16, 17, 19, 18, 26, 24, 27, 25, 22, 20, 23, 21, 32, 34, 33, 35, 31, 29, 30, 28, 42, 40, 43, 41, 38,
1227  36, 39, 37, 46, 47, 44, 45, 49, 48, 51, 50, 56, 57, 58, 59, 52, 53, 54, 55, 62, 63, 61, 60, 66, 64, 67, 65, 70, 71, 69, 68, 74, 72, 75, 73, 78, 79, 77,
1228  76, 82, 83, 81, 80, 86, 84, 87, 85, 90, 91, 89, 88, 94, 92, 95, 93, 96, 103, 101, 104, 102, 99, 97, 100, 98, 106, 105, 109, 107, 110, 108, 117, 115,
1229  118, 116, 113, 111, 114, 112, 120, 119, 123, 121, 124, 122, 128, 127, 125, 126, 130, 129, 131, 135, 132, 133, 134, 139, 136, 137, 138, 142, 143, 141,
1230  140, 144, 146, 145};
1231 
1232  for(int x = 0; x < FirstUnusedSpeedTagNumber; x++)
1233  {
1234  FlipArray[x] = InternalFlipArray[x];
1235  MirrorArray[x] = InternalMirrorArray[x];
1236  RotRightArray[x] = InternalRotRightArray[x];
1237  RotLeftArray[x] = InternalRotLeftArray[x];
1238  }
1239 }
1240 
1241 // ---------------------------------------------------------------------------
1243 {
1244 // delete TrackVectorPtr;
1245 // delete FixedTrackArrayPtr;
1246  TTrack::TUserGraphicMap::iterator UGMIt = Track->UserGraphicMap.begin();
1247 
1248  while(UGMIt != Track->UserGraphicMap.end()) // delete all the TPictures in the map
1249  {
1250  delete UGMIt->second;
1251  UGMIt++;
1252  }
1253  delete GapFlashGreen;
1254  delete GapFlashRed;
1255  // all the rest are cleared by the relevant automatic destructors
1256 }
1257 
1258 // ---------------------------------------------------------------------------
1259 
1261 {
1262  Graphics::TBitmap *TrackImageArray[FirstUnusedSpeedTagNumber] =
1263  {
1264 // loc 0 not used, set to bmSolidBgnd
1268 // no 17 not used (was used for text in early phases), set to bmSolidBgnd
1288 
1289  Graphics::TBitmap *SmallTrackImageArray[FirstUnusedSpeedTagNumber] =
1290  {
1291 // loc 0 not used, set to smSolidBgnd
1295 // no 17 not used (was used for text in early phases), set to smSolidBgnd
1314  RailGraphics->smTransparent, RailGraphics->sm129, RailGraphics->sm130 // use small footbridges for underpasses
1315  };
1316 
1317 // track types
1318  TTrackType TrackTypeArray[FirstUnusedSpeedTagNumber] =
1319  {Erase, // 1 0
1320  Simple, Simple, Simple, Simple, Simple, Simple, // 6 1-6
1321  Points, Points, Points, Points, Points, Points, Points, Points, // 8 7-14
1322  Crossover, Crossover, // 2 15-16
1323  Unused, // 17 (was for text in earlier development) //1 17
1326  Crossover, Crossover, Crossover, Crossover, // 4 44-47
1330  Platform, Platform, Platform, Platform, // 4 76-79
1333  Concourse, // 1 96
1336  Simple, Simple, Simple, Simple, // 4 125-128
1337  FootCrossing, FootCrossing, // 2 129-130
1338  NamedNonStationLocation, // 1 131
1339  Points, Points, Points, Points, Points, Points, Points, Points, // 8 132-139
1340  Simple, Simple, Simple, Simple, // 4 140-143
1341  LevelCrossing, // 1 144
1342  FootCrossing, FootCrossing // 2 145 & 146
1343  };
1344 
1345 // links
1346  int Links[FirstUnusedSpeedTagNumber][4] =
1347  {{-1, -1, -1, -1}, // erase element
1348  {4, 6, -1, -1}, {2, 8, -1, -1}, {6, 8, -1, -1}, {4, 8, -1, -1}, {2, 6, -1, -1}, {2, 4, -1, -1}, // simple
1349  {4, 6, 4, 2}, {6, 4, 6, 2}, {4, 6, 4, 8}, {6, 4, 6, 8}, {8, 2, 8, 4}, {8, 2, 8, 6}, {2, 8, 2, 4}, {2, 8, 2, 6}, // points
1350 // points always have links 0 & 2 = lead, link 1 = trailing straight, link 3 = trailing diverging
1351  {4, 6, 2, 8}, {1, 9, 3, 7}, // crossover links 0 & 1 = diagonal top left to Bottom right, then horizontal, then vertical
1352  {-1, -1, -1, -1}, // unused
1353  {3, 7, -1, -1}, {1, 9, -1, -1}, {7, 6, -1, -1}, {4, 9, -1, -1}, {1, 6, -1, -1}, {4, 3, -1, -1}, {3, 8, -1, -1}, {1, 8, -1, -1}, {2, 9, -1, -1},
1354  {2, 7, -1, -1}, // simple
1355  {4, 6, 4, 3}, {6, 4, 6, 1}, {4, 6, 4, 9}, {6, 4, 6, 7}, {8, 2, 8, 1}, {8, 2, 8, 3}, {2, 8, 2, 7}, {2, 8, 2, 9}, {9, 1, 9, 2}, {7, 3, 7, 2}, {3, 7, 3, 8
1356  }, {1, 9, 1, 8}, {9, 1, 9, 4}, {7, 3, 7, 6}, {3, 7, 3, 4}, {1, 9, 1, 6}, // points
1357 // points always have links 0 & 2 = lead, link 1 = trailing straight (or left diverging if no straight), link 3 = trailing diverging
1358 // (or right diverging if no straight)
1359  {1, 9, 2, 8}, {2, 8, 3, 7}, {4, 6, 3, 7}, {1, 9, 4, 6}, // crossover links 0 & 1 = diagonal top left to Bottom right, then horizontal, then vertical
1360  {2, 8, 4, 6}, {4, 6, 2, 8}, {3, 7, 1, 9}, {1, 9, 3, 7}, {2, 8, 1, 9}, {2, 8, 3, 7}, {3, 7, 2, 8}, {1, 9, 2, 8}, {4, 6, 3, 7}, {4, 6, 1, 9}, {1, 9, 4, 6
1361  }, {3, 7, 4, 6}, // bridge, links 2 & 3 = underbridge
1362  {4, 6, -1, -1}, {6, 4, -1, -1}, {8, 2, -1, -1}, {2, 8, -1, -1}, {1, 9, -1, -1}, {3, 7, -1, -1}, {7, 3, -1, -1}, {9, 1, -1, -1
1363  }, // buffers - position 0 = buffer
1364  {4, 6, -1, -1}, {4, 6, -1, -1}, {2, 8, -1, -1}, {2, 8, -1, -1}, {1, 9, -1, -1}, {3, 7, -1, -1}, {3, 7, -1, -1}, {1, 9, -1, -1
1365  }, // signals (need Config to determine signal end, see below)
1366  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, // platform
1367  {4, 6, -1, -1}, {6, 4, -1, -1}, {8, 2, -1, -1}, {2, 8, -1, -1}, {1, 9, -1, -1}, {3, 7, -1, -1}, {7, 3, -1, -1}, {9, 1, -1, -1
1368  }, // continuation - position 0 = continuation
1369  {4, 6, -1, -1}, {6, 4, -1, -1}, {8, 2, -1, -1}, {2, 8, -1, -1}, {1, 9, -1, -1}, {3, 7, -1, -1}, {7, 3, -1, -1}, {9, 1, -1, -1
1370  }, // gapjump - position 0 = gap
1371  {-1, -1, -1, -1}, // Concourse
1372  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1},
1373  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1},
1374  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1},
1375  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, // Parapets
1376  {4, 6, -1, -1}, {4, 6, -1, -1}, {2, 8, -1, -1}, {2, 8, -1, -1}, // arrows
1377  {4, 6, -1, -1}, {2, 8, -1, -1}, // footbridges
1378  {-1, -1, -1, -1}, // NamedNonStationLocation
1379  {8, 1, 8, 3}, {4, 3, 4, 9}, {2, 9, 2, 7}, {6, 7, 6, 1}, {9, 4, 9, 2}, {7, 2, 7, 6}, {1, 6, 1, 8}, {3, 8, 3, 4}, // points without straight legs
1380 // these points have links 0 & 2 = lead, link 1 = LH trailing, link 3 = RH trailing
1381  {3, 7, -1, -1}, {3, 7, -1, -1}, {1, 9, -1, -1}, {1, 9, -1, -1}, // arrowed diagonals
1382  {-1, -1, -1, -1}, // level crossing
1383  {4, 6, -1, -1}, {2, 8, -1, -1}, // underpasses/surface crossings
1384  };
1385 
1387  {{NotSet, NotSet, NotSet, NotSet}, // unused
1391  {Lead, Trail, Lead, Trail}, {Lead, Trail, Lead, Trail}, {Lead, Trail, Lead, Trail}, // points
1393  {NotSet, NotSet, NotSet, NotSet}, // unused
1397  {Connection, Connection, NotSet, NotSet}, // simple
1401  {Lead, Trail, Lead, Trail}, // points
1403  {CrossConn, CrossConn, CrossConn, CrossConn}, // crossover
1412  }, // signals (signal at exit end in forward direction)
1416  }, // continuation
1419  {NotSet, NotSet, NotSet, NotSet}, // Concourse
1428  {Connection, Connection, NotSet, NotSet}, // Arrows
1430  {NotSet, NotSet, NotSet, NotSet}, // NamedNonStationLocation
1432  {Lead, Trail, Lead, Trail}, {Lead, Trail, Lead, Trail}, {Lead, Trail, Lead, Trail}, // points
1434  {Connection, Connection, NotSet, NotSet}, // Arrowed diagonals
1435  {NotSet, NotSet, NotSet, NotSet}, // Level crossing
1436  {Connection, Connection, NotSet, NotSet}, {Connection, Connection, NotSet, NotSet} // Underpasses/surface crossings
1437  };
1438 
1439  for(int x = 0; x < 17; x++)
1440  {
1441  FixedTrackPiece[x] = TFixedTrackPiece(x, TrackTypeArray[x], Links[x], Configs[x], TrackImageArray[x], SmallTrackImageArray[x]);
1442  }
1443  FixedTrackPiece[17] = TFixedTrackPiece(17, TrackTypeArray[17], Links[17], Configs[17], 0, 0);
1444 // 17 was the old text value so don't want any graphics (now disused)
1445  for(int x = 18; x < FirstUnusedSpeedTagNumber; x++)
1446  {
1447  FixedTrackPiece[x] = TFixedTrackPiece(x, TrackTypeArray[x], Links[x], Configs[x], TrackImageArray[x], SmallTrackImageArray[x]);
1448  }
1449 }
1450 
1451 // ---------------------------------------------------------------------------
1452 TGraphicElement::TGraphicElement(): OverlayPlotted(false), OriginalLoaded(false), ScreenSourceSet(false), ScreenGraphicLoaded(false),
1453  ExistingGraphicLoaded(false), Width(16), Height(16)
1454 {
1455  OriginalGraphic = new Graphics::TBitmap;
1456  OriginalGraphic->PixelFormat = pf8bit;
1457  OriginalGraphic->Width = Width;
1458  OriginalGraphic->Height = Height;
1459  OriginalGraphic->Transparent = false; // seems to default to false but set it to be sure, so no need to plot a blank before each replot
1460 }
1461 
1462 // ---------------------------------------------------------------------------
1463 
1464 TGraphicElement::TGraphicElement(int WidthIn, int HeightIn): OverlayPlotted(false), OriginalLoaded(false), ScreenSourceSet(false), ScreenGraphicLoaded(false),
1465  ExistingGraphicLoaded(false), Width(WidthIn), Height(HeightIn)
1466 {
1467  OriginalGraphic = new Graphics::TBitmap;
1468  OriginalGraphic->PixelFormat = pf8bit;
1469  OriginalGraphic->Width = Width;
1470  OriginalGraphic->Height = Height;
1471  OriginalGraphic->Transparent = false; // seems to default to false but set it to be sure, so no need to plot a blank before each replot
1472 }
1473 
1474 // ---------------------------------------------------------------------------
1475 
1477 {
1478  delete OriginalGraphic;
1479 }
1480 
1481 // ---------------------------------------------------------------------------
1482 
1483 void TGraphicElement::SetScreenHVSource(int Caller, int HPosIn, int VPosIn)
1484 {
1485  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetScreenHVSource," + AnsiString(HPosIn) + "," + AnsiString(VPosIn));
1486  HPos = HPosIn; // HPos & VPos are members of TGraphicElement
1487  VPos = VPosIn;
1488  int Left, Top; // can't use e.g. PointFlash.SourceRect.Left & Top directly as references as don't exist as objects in their own right
1489 
1490  Track->GetScreenPositionsFromTruePos(2, Left, Top, HPos, VPos);
1491  SourceRect.init(Left, Top, Left + Width, Top + Height);
1492  ScreenSourceSet = true;
1493  Utilities->CallLogPop(422);
1494 }
1495 
1496 // ---------------------------------------------------------------------------
1497 
1499 {
1500  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadOriginalScreenGraphic");
1501  if(!OverlayLoaded)
1502  {
1503  throw Exception("Overlay not loaded in TGraphicElement::LoadOriginalScreenGraphic()");
1504  }
1505  if((OverlayGraphic->Width != 16) || (OverlayGraphic->Height != 16))
1506  {
1507  throw Exception("Overlay not 16x16 in TGraphicElement::LoadOriginalScreenGraphic()");
1508  }
1509  if(!ScreenSourceSet)
1510  {
1511  throw Exception("Source not set in TGraphicElement::LoadOriginalScreenGraphic()");
1512  }
1513  if(ExistingGraphicLoaded) // can only call one of the load functions
1514  {
1515  throw Exception("ExistingGraphicLoaded in TGraphicElement::LoadOriginalScreenGraphic()");
1516  }
1517  if(OverlayPlotted) // don't load from screen if overlay plotted
1518  {
1519  Utilities->CallLogPop(775);
1520  return;
1521  }
1522  TRect DestRect(0, 0, Width, Height);
1523 
1525  OriginalLoaded = true;
1526  ScreenGraphicLoaded = true;
1527  Utilities->CallLogPop(423);
1528 }
1529 
1530 // ---------------------------------------------------------------------------
1531 
1532 void TGraphicElement::LoadOriginalExistingGraphic(int Caller, int HOffset, int VOffset, int WidthIn, int HeightIn, Graphics::TBitmap *Graphic)
1533 /*
1534  Overrides size set in the constructor, SourceRect & HPos & VPos in SetScreenHVSource
1535 */
1536 {
1537  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadOriginalExistingGraphic," + AnsiString(HOffset) + "," +
1538  AnsiString(VOffset) + "," + AnsiString(WidthIn) + "," + AnsiString(HeightIn));
1539  if(!OverlayLoaded)
1540  {
1541  throw Exception("Overlay not loaded in TGraphicElement::LoadOriginalExistingGraphic()");
1542  }
1543  if(!ScreenSourceSet) // has to be called to set HPos & VPos
1544  {
1545  throw Exception("Source not set in TGraphicElement::LoadOriginalExistingGraphic()");
1546  }
1547  if(ScreenGraphicLoaded) // can only call one of the load functions
1548  {
1549  throw Exception("ScreenGraphicLoaded in TGraphicElement::LoadOriginalExistingGraphic()");
1550  }
1551  Width = WidthIn;
1552  Height = HeightIn;
1553  OriginalGraphic->Width = Width;
1554  OriginalGraphic->Height = Height;
1555  HPos += HOffset; // originally set in SetScreenHVSource to position of H & V locations
1556  VPos += VOffset;
1557  TRect DestRect(0, 0, Width, Height);
1558 
1559  SourceRect.init(HOffset, VOffset, HOffset + Width, VOffset + Height);
1560  OriginalGraphic->Canvas->CopyRect(DestRect, Graphic->Canvas, SourceRect);
1561  OriginalLoaded = true;
1562  ExistingGraphicLoaded = true;
1563  Utilities->CallLogPop(424);
1564 }
1565 
1566 // ---------------------------------------------------------------------------
1567 
1568 void TGraphicElement::LoadOverlayGraphic(int Caller, Graphics::TBitmap *Overlay)
1569 {
1570  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadOverlayGraphic,");
1571  OverlayGraphic = Overlay;
1572  OverlayLoaded = true;
1573  Utilities->CallLogPop(425);
1574 }
1575 
1576 // ---------------------------------------------------------------------------
1577 
1579 {
1580  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotOverlay,");
1581  if(!OverlayLoaded)
1582  {
1583  throw Exception("Overlay not loaded in TGraphicElement::PlotOverlay()");
1584  }
1585  if(!OverlayPlotted)
1586  {
1587  Disp->PlotOutput(35, HPos, VPos, OverlayGraphic); // plot overlay
1588  Disp->Update();
1589  OverlayPlotted = true;
1590  }
1591  Utilities->CallLogPop(426);
1592 }
1593 
1594 // ---------------------------------------------------------------------------
1595 
1597 {
1598  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotOriginal,");
1599  if(OverlayPlotted)
1600  {
1601  if(!OriginalLoaded) // this comes after OverlayPlotted because may wish to 'try' to plot original even
1602  // when it isn't loaded in case it had been plotted - e.g. when change user modes
1603  {
1604  throw Exception("Original not loaded in TGraphicElement::PlotOriginal()");
1605  }
1606  Disp->PlotOutput(36, HPos, VPos, OriginalGraphic); // replot original
1607  Disp->Update(); // This was commented out originally but when in flashes much less frequent when points changing manually
1608  OverlayPlotted = false;
1609  }
1610  Utilities->CallLogPop(427);
1611 }
1612 
1613 // ---------------------------------------------------------------------------
1614 
1616 {
1617  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NoTrack");
1618  bool TrackPresent = false;
1619 
1620  if(InactiveTrackVector.size() != 0)
1621  {
1622  Utilities->CallLogPop(1333);
1623  return false;
1624  }
1625  else if(TrackVector.size() == 0)
1626  {
1627  Utilities->CallLogPop(1334);
1628  return true;
1629  }
1630  else
1631  {
1632  for(unsigned int x = 0; x < TrackVector.size(); x++)
1633  {
1634  if((TrackVector.at(x).SpeedTag != 0))
1635  TrackPresent = true;
1636  }
1637  }
1638  Utilities->CallLogPop(1335);
1639  return !TrackPresent;
1640 }
1641 
1642 // ---------------------------------------------------------------------------
1643 
1644 bool TTrack::NoActiveTrack(int Caller)
1645 {
1646  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NoActiveTrack");
1647  bool TrackPresent = false;
1648 
1649  if(TrackVector.size() == 0)
1650  {
1651  Utilities->CallLogPop(1582);
1652  return true;
1653  }
1654  else
1655  {
1656  for(unsigned int x = 0; x < TrackVector.size(); x++)
1657  {
1658  if((TrackVector.at(x).SpeedTag != 0))
1659  TrackPresent = true;
1660  break;
1661  }
1662  }
1663  Utilities->CallLogPop(1583);
1664  return !TrackPresent;
1665 }
1666 
1667 // ---------------------------------------------------------------------------
1668 
1669 void TTrack::EraseTrackElement(int Caller, int HLocInput, int VLocInput, int &ErasedTrackVectorPosition, bool &TrackEraseSuccessfulFlag, bool InternalChecks)
1670 {
1671  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EraseTrackElement," + AnsiString(HLocInput) + "," +
1672  AnsiString(VLocInput) + "," + AnsiString((short)InternalChecks));
1673  TrackEraseSuccessfulFlag = false;
1674 // TrackEraseSuccessfulFlag used for both track element and inactive element erase,
1675 // since have to match platforms as well as track
1676 // used to set TrackFinished to false if an element erased
1677 
1678  ErasedTrackVectorPosition = -1; // marker for no element erased
1679  AnsiString SName = "", ErrorString;
1681  THVPair TrackMapKeyPair, InactiveTrackMapKeyPair;
1682  TTrackMapIterator TrackMapPtr;
1683  TInactiveTrack2MultiMapIterator InactiveTrack2MultiMapIterator;
1684 
1685  if(TrackVector.size() != 0)
1686  {
1687  TrackMapKeyPair.first = HLocInput;
1688  TrackMapKeyPair.second = VLocInput;
1689  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
1690  if(TrackMapPtr != TrackMap.end())
1691  {
1692  bool FoundFlag;
1693  int VecPos = GetVectorPositionFromTrackMap(37, HLocInput, VLocInput, FoundFlag);
1694  if(FoundFlag) // should find it as it's in the map
1695  {
1696  if(TrackElementAt(629, VecPos).FixedNamedLocationElement) // footcrossings only
1697  {
1698  SName = TrackElementAt(1, VecPos).LocationName;
1699  SNIt = FindNamedElementInLocationNameMultiMap(7, SName, TrackVector.begin() + VecPos, ErrorString);
1700  if(ErrorString != "")
1701  {
1702  throw Exception(ErrorString + " for EraseTrackElement 1");
1703  }
1704  LocationNameMultiMap.erase(SNIt);
1705  }
1706 
1707  TrackVector.erase(TrackVector.begin() + TrackMapPtr->second);
1708  // ensure erase vector element before map element as iterator no longer valid after a map erase
1709  TrackMap.erase(TrackMapPtr);
1710  FixedTrackArray.FixedTrackPiece[0].PlotFixedTrackElement(2, HLocInput, VLocInput); // plot a blank element
1711  // need to decrement all map element position values that lie above VecPos, since vector positions above this have all moved down one
1713  ResetAnyNonMatchingGaps(1); // in case the deleted element was a set gap
1714  if(SName != "")
1715  {
1716  EraseLocationAndActiveTrackElementNames(5, SName); // this instead of SearchForAndUpdateLocationName later (saves time)
1717  int HPos, VPos;
1718  if(TextHandler->FindText(1, SName, HPos, VPos))
1719  {
1720  if(TextHandler->TextErase(5, HPos, VPos))
1721  {;
1722  } // condition not used
1723  }
1724  }
1725  ErasedTrackVectorPosition = VecPos;
1726  TrackEraseSuccessfulFlag = true;
1727  }
1728  }
1729  }
1730 
1731  if(InactiveTrackVector.size() != 0)
1732  {
1733  unsigned int VecPos;
1734  InactiveTrackMapKeyPair.first = HLocInput;
1735  InactiveTrackMapKeyPair.second = VLocInput;
1736  InactiveTrack2MultiMapIterator = InactiveTrack2MultiMap.find(InactiveTrackMapKeyPair);
1737  if(InactiveTrack2MultiMapIterator != InactiveTrack2MultiMap.end())
1738  {
1739  SName = "";
1740  VecPos = InactiveTrack2MultiMapIterator->second;
1741  if(InactiveTrackElementAt(0, VecPos).FixedNamedLocationElement)
1742  {
1743  SName = InactiveTrackElementAt(1, VecPos).LocationName;
1744  SNIt = FindNamedElementInLocationNameMultiMap(2, SName, InactiveTrackVector.begin() + VecPos, ErrorString);
1745  if(ErrorString != "")
1746  {
1747  throw Exception(ErrorString + " for EraseTrackElement 2A");
1748  }
1749  LocationNameMultiMap.erase(SNIt);
1750  }
1751  InactiveTrackVector.erase(InactiveTrackVector.begin() + InactiveTrack2MultiMapIterator->second); // if inactive can erase immediately
1752  // ensure erase vector element before map element as iterator no longer valid after a map erase
1753  InactiveTrack2MultiMap.erase(InactiveTrack2MultiMapIterator);
1754  FixedTrackArray.FixedTrackPiece[0].PlotFixedTrackElement(1, HLocInput, VLocInput); // plot a blank element
1755  // need to decrement all map element position values that lie above VecPos, since vector positions above this have all moved down one
1757  TrackEraseSuccessfulFlag = true;
1758  if(SName != "")
1759  {
1760  EraseLocationAndActiveTrackElementNames(3, SName); // this instead of SearchForAndUpdateLocationName later (saves time)
1761  int HPos, VPos;
1762  if(TextHandler->FindText(2, SName, HPos, VPos))
1763  {
1764  if(TextHandler->TextErase(6, HPos, VPos))
1765  {;
1766  } // condition not used
1767  }
1768  }
1769  }
1770 
1771  if(InactiveTrackVector.size() != 0) // need to check again as last access may have erased the last element
1772  {
1773  InactiveTrack2MultiMapIterator = InactiveTrack2MultiMap.find(InactiveTrackMapKeyPair); // may be up to 2 elements (platforms) at same location
1774  if(InactiveTrack2MultiMapIterator != InactiveTrack2MultiMap.end())
1775  {
1776  SName = "";
1777  VecPos = InactiveTrack2MultiMapIterator->second;
1778  if(InactiveTrackElementAt(2, VecPos).FixedNamedLocationElement)
1779  {
1780  SName = InactiveTrackElementAt(3, VecPos).LocationName;
1781  SNIt = FindNamedElementInLocationNameMultiMap(3, SName, InactiveTrackVector.begin() + VecPos, ErrorString);
1782  if(ErrorString != "")
1783  {
1784  throw Exception(ErrorString + " for EraseTrackElement 2B");
1785  }
1786  LocationNameMultiMap.erase(SNIt);
1787  }
1788  InactiveTrackVector.erase(InactiveTrackVector.begin() + InactiveTrack2MultiMapIterator->second); // if inactive can erase immediately
1789  InactiveTrack2MultiMap.erase(InactiveTrack2MultiMapIterator);
1790  // need to decrement all map element position values that lie above VecPos, since vector positions above this have all moved down one
1792  if(SName != "")
1793  {
1794  EraseLocationAndActiveTrackElementNames(4, SName); // this instead of SearchForAndUpdateLocationName later (saves time)
1795  int HPos, VPos;
1796  if(TextHandler->FindText(3, SName, HPos, VPos))
1797  {
1798  if(TextHandler->TextErase(7, HPos, VPos))
1799  {;
1800  } // condition not used
1801  }
1802  }
1803  }
1804  }
1805  }
1806  if(TrackEraseSuccessfulFlag)
1807  {
1808  CalcHLocMinEtc(2);
1809  SetTrackFinished(false);
1810  }
1811  if(InternalChecks)
1812  {
1813  CheckMapAndTrack(1); // test
1814  CheckMapAndInactiveTrack(1); // test
1815  CheckLocationNameMultiMap(6); // test
1816  }
1817  Utilities->CallLogPop(428);
1818 }
1819 
1820 // ---------------------------------------------------------------------------
1821 
1822 void TTrack::PlotAndAddTrackElement(int Caller, int CurrentTag, int Aspect, int HLocInput, int VLocInput, bool &TrackLinkingRequiredFlag, bool InternalChecks)
1823  // TrackLinkingRequiredFlag only relates to elements that require track linking after plotting - used to set TrackFinished
1824  // to false in calling function. New at v2.2.0 new parameter 'Aspect' to ensure signals plotted with correct number of aspects (for pasting)
1825  // and also when zero and combined with SignalPost to indicate that adding track rather than pasting
1826 {
1827  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotAndAddTrackElement," + AnsiString(CurrentTag) + "," +
1828  AnsiString(HLocInput) + "," + AnsiString(VLocInput) + "," + AnsiString((short)InternalChecks));
1829  bool PlatAllowedFlag = false;
1830 
1831  TrackLinkingRequiredFlag = false;
1832 /*
1833  Not erase, that covered separately.
1834  First check if Current SpeedButton assigned, then check if a platform and only
1835  permit if an appropriate trackpiece already there & not a same platform there.
1836  - can't enter a platform without track first.
1837  Then for non-platforms, check if a track piece already present at location &
1838  reject if so.
1839 */
1840 
1841  TLocationNameMultiMapEntry LocationNameEntry;
1842 
1843  LocationNameEntry.first = "";
1844  if(CurrentTag == 0)
1845  {
1846  Utilities->CallLogPop(429);
1847  return; // not assigned yet
1848  }
1849 
1850  TTrackElement TempTrackElement(FixedTrackArray.FixedTrackPiece[CurrentTag]);
1851 
1852  TempTrackElement.HLoc = HLocInput;
1853  TempTrackElement.VLoc = VLocInput;
1854  SetElementID(1, TempTrackElement); // TempTrackElement is the one to be added
1855 // new at version 0.6 - set signal aspect depending on build mode
1856 
1857  if(TempTrackElement.TrackType == SignalPost)
1858  {
1859  if(Aspect == 0) // new at v2.2.0, '0' and SignalPost together means that track being added & not pasted, because when
1860  // pasting a SignalPost can only have values 1 to 4
1861  {
1863  {
1864  TempTrackElement.SigAspect = TTrackElement::ThreeAspect;
1865  }
1867  {
1868  TempTrackElement.SigAspect = TTrackElement::TwoAspect;
1869  }
1871  {
1872  TempTrackElement.SigAspect = TTrackElement::GroundSignal;
1873  }
1874  else
1875  {
1876  TempTrackElement.SigAspect = TTrackElement::FourAspect;
1877  }
1878  }
1879  else if(Aspect == 1)
1880  TempTrackElement.SigAspect = TTrackElement::GroundSignal;
1881  else if(Aspect == 2)
1882  TempTrackElement.SigAspect = TTrackElement::TwoAspect;
1883  else if(Aspect == 3)
1884  TempTrackElement.SigAspect = TTrackElement::ThreeAspect;
1885  else
1886  TempTrackElement.SigAspect = TTrackElement::FourAspect;
1887  }
1888 
1889  bool FoundFlag = false, InactiveFoundFlag = false, NonStationOrLevelCrossingPresent = false, PlatformPresent = false;
1890  int VecPos = GetVectorPositionFromTrackMap(12, HLocInput, VLocInput, FoundFlag); // active track already there
1891  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(5, HLocInput, VLocInput, InactiveFoundFlag); // inactive track already there
1892  int InactiveSpeedTag1 = 0, InactiveSpeedTag2 = 0;
1893 
1894  if(InactiveFoundFlag) // check if a LocationName already there & if so disallow platform
1895  {
1897  NonStationOrLevelCrossingPresent = true;
1898  if(InactiveTrackElementAt(117, IMPair.first).TrackType == LevelCrossing)
1899  NonStationOrLevelCrossingPresent = true;
1900  if(InactiveTrackElementAt(5, IMPair.first).TrackType == Platform)
1901  PlatformPresent = true;
1902  // no need to check IMPair.second since if that exists it is because .first is a platform
1903  InactiveSpeedTag1 = InactiveTrackElementAt(6, IMPair.first).SpeedTag;
1904  InactiveSpeedTag2 = InactiveTrackElementAt(7, IMPair.second).SpeedTag; // note .first & .second will be same if only one present
1905  }
1906 
1907 // check platforms
1908  if(TempTrackElement.TrackType == Platform)
1909  {
1910  if(FoundFlag) // active track element already there
1911  {
1912  if(InactiveFoundFlag && ((TempTrackElement.SpeedTag == InactiveSpeedTag1) || (TempTrackElement.SpeedTag == InactiveSpeedTag2)))
1913  {;
1914  }
1915  // same platform type already there so above keeps PlatAllowedFlag false
1916  else if((TempTrackElement.SpeedTag == 76) && (TopPlatAllowed.Contains(TrackVector.at(VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
1917  // won't allow a same platform, as TopPlatAllowed not valid for a same platform <--NO, only checks active track, same plat disallowed by first line after if(FoundFlag)
1918  {
1919  PlatAllowedFlag = true;
1920  }
1921  else if((TempTrackElement.SpeedTag == 77) && (BotPlatAllowed.Contains(TrackVector.at(VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
1922  {
1923  PlatAllowedFlag = true;
1924  }
1925  else if((TempTrackElement.SpeedTag == 78) && (LeftPlatAllowed.Contains(TrackVector.at(VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
1926  {
1927  PlatAllowedFlag = true;
1928  }
1929  else if((TempTrackElement.SpeedTag == 79) && (RightPlatAllowed.Contains(TrackVector.at(VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
1930  {
1931  PlatAllowedFlag = true;
1932  }
1933  if(PlatAllowedFlag)
1934  {
1935  TrackLinkingRequiredFlag = true; // needed in order to call LinkTrack
1936  TrackPush(1, TempTrackElement);
1937  SearchForAndUpdateLocationName(1, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
1938  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
1939  // Must be called AFTER TrackPush
1940  // No need to plot the element - Clearand ... called after this function called
1941  // set corresponding track element length to 100m & give message if was different drop in v2.4.0
1942  // note can only be Length01 since even if points then only the straight part can be adjacent to the platform
1943 // drop in v2.4.0 if(TrackElementAt(2, VecPos).Length01 != DefaultTrackLength) ShowMessage("Note: The track element at this location has a length of " +
1944 // AnsiString(TrackElementAt(3, VecPos).Length01) + "m. It will be reset to 100m since all platform track lengths are fixed at 100m");
1945 // TrackElementAt(4, VecPos).Length01 = DefaultTrackLength;
1946  if(InternalChecks)
1947  {
1948  CheckMapAndInactiveTrack(5); // test
1949  CheckLocationNameMultiMap(4); // test
1950  }
1951  Utilities->CallLogPop(430);
1952  return;
1953  }
1954  } // if(FoundFlag)
1955  Utilities->CallLogPop(431);
1956  return;
1957  } // if platform
1958 
1959 // check if element is a LocationName - OK if placed on an allowable track element, or on a blank element
1960  if(TempTrackElement.TrackType == NamedNonStationLocation)
1961  {
1962  if((FoundFlag && (NameAllowed.Contains(TrackVector.at(VecPos).SpeedTag)) && !PlatformPresent && !InactiveFoundFlag) ||
1963  (!FoundFlag && !InactiveFoundFlag))
1964  // need to add && !NonStationOrLevelCrossingPresent, or better - !InactiveFoundFlag to above FoundFlag condition <-- OK done
1965  {
1966  TrackLinkingRequiredFlag = true; // needed in case have named a continuation, need to check if adjacent element named
1967  TrackPush(2, TempTrackElement);
1968  SearchForAndUpdateLocationName(2, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
1969  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
1970  if(VecPos > -1) // need to allow for non-station named locations that aren't on tracks
1971  {
1972 // drop in v2.4.0 if(TrackElementAt(830, VecPos).Length01 != DefaultTrackLength) ShowMessage("Note: The track element at this location has a length of " +
1973 // AnsiString(TrackElementAt(831, VecPos).Length01) + "m. It will be reset to 100m since all named location track lengths are fixed at 100m");
1974 // TrackElementAt(832, VecPos).Length01 = DefaultTrackLength; //NB named locations can only be placed at one track elements
1975  }
1976  if(InternalChecks)
1977  {
1978  CheckMapAndInactiveTrack(11); // test
1979  CheckLocationNameMultiMap(12); // test
1980  }
1981  Utilities->CallLogPop(432);
1982  return;
1983  }
1984  else
1985  {
1986  Utilities->CallLogPop(433);
1987  return;
1988  }
1989  }
1990 
1991 // check if a level crossing - OK if placed on a plain straight track
1992  if(TempTrackElement.TrackType == LevelCrossing)
1993  {
1994  if(FoundFlag && (LevelCrossingAllowed.Contains(TrackVector.at(VecPos).SpeedTag)) && !PlatformPresent && !InactiveFoundFlag)
1995  {
1996  TrackPush(11, TempTrackElement);
1997  PlotRaisedLinkedLevelCrossingBarriers(0, TrackVector.at(VecPos).SpeedTag, TempTrackElement.HLoc, TempTrackElement.VLoc, Display);
1998 // no need for reference to LC element as can't be open
1999  TrackLinkingRequiredFlag = true;
2000  Utilities->CallLogPop(1907);
2001  return;
2002  }
2003  else
2004  {
2005  Utilities->CallLogPop(1906);
2006  return; // was a level crossing but can't place it for some reason
2007  }
2008  }
2009 
2010 // check if another element already there
2011  else if(FoundFlag || InactiveFoundFlag)
2012  {
2013  Utilities->CallLogPop(434);
2014  return; // something already there (active or inactive track)
2015  }
2016 
2017 // add LocationName if a FixedNamedLocationElement by checking for any adjacent names, then give all linked named location
2018 // elements the same name - in case had linked 2 separately named locations - all get the one name that it finds
2019 // first from an adjacent element search, also non-named location elements at platform locations have timetable name set
2020 // do this after pushed into vector so that can use EnterLocationName
2021 
2022  if(TempTrackElement.FixedNamedLocationElement) // concourse or footcrossing (platforms & named non-station locations already dealt with)
2023  {
2024  TrackPush(3, TempTrackElement);
2025  SearchForAndUpdateLocationName(3, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2026  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2027  }
2028  else if(TempTrackElement.TrackType == Points)
2029  {
2030  TrackPush(4, TempTrackElement);
2031  bool BothPointFillets = true;
2032  PlotPoints(6, TempTrackElement, Display, BothPointFillets);
2033  }
2034  else if(TempTrackElement.TrackType == SignalPost)
2035  {
2036  TrackPush(10, TempTrackElement);
2037  PlotSignal(12, TempTrackElement, Display);
2038  }
2039  else
2040  {
2041  TrackPush(5, TempTrackElement);
2042  TempTrackElement.PlotVariableTrackElement(1, Display); // all named locations already dealt with so no ambiguity between striped & non-striped
2043  }
2044  if((TempTrackElement.TrackType != Concourse) && (TempTrackElement.TrackType != Parapet))
2045  TrackLinkingRequiredFlag = true; // plats & NamedLocs aleady dealt with
2046  if(InternalChecks)
2047  {
2048  CheckMapAndTrack(2); // test
2049  CheckMapAndInactiveTrack(2); // test
2050  CheckLocationNameMultiMap(5); // test
2051  }
2052  Utilities->CallLogPop(2062);
2053 }
2054 
2055 // ---------------------------------------------------------------------------
2056 
2057 void TTrack::PlotPastedTrackElementWithAttributes(int Caller, TTrackElement TempTrackElement, int HLocInput, int VLocInput, bool &TrackLinkingRequiredFlag,
2058  bool InternalChecks)
2059  // new at v2.2.0 - similar to above but keeping speed & length attributes (for pasting) and also pastes location names
2060  // NB experimental: - need to change all caller numbers & check thoroughly if release
2061  // as is if single elements have location or platform names then have message that names fail to align when mouse over
2062  // need to deal with this if release - it's because ActiveTrackElementName is cleared in the new function, if not a single element
2063  // then set when call SearchForAndUpdateLocationName. Maybe instead of clearing can set to the InactiveTrackElementName at the same location?
2064 {
2065  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotPastedTrackElementWithAttributes," + AnsiString(HLocInput) + "," +
2066  AnsiString(VLocInput) + "," + AnsiString((short)InternalChecks));
2067  bool PlatAllowedFlag = false;
2068 
2069  TrackLinkingRequiredFlag = false;
2070 /*
2071  Not erase, that covered separately.
2072  First check if Current SpeedButton assigned, then check if a platform and only
2073  permit if an appropriate trackpiece already there & not a same platform there.
2074  - can't enter a platform without track first.
2075  Then for non-platforms, check if a track piece already present at location &
2076  reject if so.
2077 */
2078 
2079  TLocationNameMultiMapEntry LocationNameEntry;
2080 
2081  LocationNameEntry.first = "";
2082  if(TempTrackElement.SpeedTag == 0)
2083  {
2084  Utilities->CallLogPop(2063);
2085  return; // not assigned yet
2086  }
2087 
2088  TempTrackElement.HLoc = HLocInput;
2089  TempTrackElement.VLoc = VLocInput;
2090  for(int x = 0; x < 4; x++) // unset any gaps
2091  {
2092  if(TempTrackElement.Config[x] == Gap)
2093  TempTrackElement.ConnLinkPos[x] = -1;
2094  TempTrackElement.Conn[x] = -1;
2095  }
2096  SetElementID(5, TempTrackElement); // TempTrackElement is the one to be added
2097 // new at version 0.6 - set signal aspect depending on build mode
2098  bool FoundFlag = false, InactiveFoundFlag = false, NonStationOrLevelCrossingPresent = false, PlatformPresent = false;
2099  int VecPos = GetVectorPositionFromTrackMap(56, HLocInput, VLocInput, FoundFlag); // active track already there
2100 
2101  // if find an active track element (as has been pasted into track vector when dealing with inactive elements in SelectVector)
2102  // )set its ActiveTrackElementName to same name as the inactive element (from SelectVector). Note that can't use LocationName
2103  // for the active track element because these aren't set
2104  // if don't do this then get a mismatch error during map checks later
2105 
2106  // if(FoundFlag) TrackElementAt(xx, VecPos).ActiveTrackElementName = TempTrackElement.LocationName; //doesn't work!!
2107 
2108  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(26, HLocInput, VLocInput, InactiveFoundFlag); // inactive track already there
2109  int InactiveSpeedTag1 = 0, InactiveSpeedTag2 = 0;
2110 
2111  if(InactiveFoundFlag) // check if a LocationName already there & if so disallow platform
2112  {
2113  if(InactiveTrackElementAt(119, IMPair.first).TrackType == NamedNonStationLocation)
2114  NonStationOrLevelCrossingPresent = true;
2115  if(InactiveTrackElementAt(120, IMPair.first).TrackType == LevelCrossing)
2116  NonStationOrLevelCrossingPresent = true;
2117  if(InactiveTrackElementAt(121, IMPair.first).TrackType == Platform)
2118  PlatformPresent = true;
2119  // no need to check IMPair.second since if that exists it is because .first is a platform
2120  InactiveSpeedTag1 = InactiveTrackElementAt(122, IMPair.first).SpeedTag;
2121  InactiveSpeedTag2 = InactiveTrackElementAt(123, IMPair.second).SpeedTag; // note .first & .second will be same if only one present
2122  }
2123 
2124 // check platforms
2125  if(TempTrackElement.TrackType == Platform)
2126  {
2127  if(FoundFlag) // active track element already there
2128  {
2129  if(InactiveFoundFlag && ((TempTrackElement.SpeedTag == InactiveSpeedTag1) || (TempTrackElement.SpeedTag == InactiveSpeedTag2)))
2130  {;
2131  }
2132  // same platform type already there so above keeps PlatAllowedFlag false
2133  else if((TempTrackElement.SpeedTag == 76) && (TopPlatAllowed.Contains(TrackVector.at(VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2134  // won't allow a same platform, as TopPlatAllowed not valid for a same platform <--NO, only checks active track, same plat disallowed by first line after if(FoundFlag)
2135  {
2136  PlatAllowedFlag = true;
2137  }
2138  else if((TempTrackElement.SpeedTag == 77) && (BotPlatAllowed.Contains(TrackVector.at(VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2139  {
2140  PlatAllowedFlag = true;
2141  }
2142  else if((TempTrackElement.SpeedTag == 78) && (LeftPlatAllowed.Contains(TrackVector.at(VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2143  {
2144  PlatAllowedFlag = true;
2145  }
2146  else if((TempTrackElement.SpeedTag == 79) && (RightPlatAllowed.Contains(TrackVector.at(VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2147  {
2148  PlatAllowedFlag = true;
2149  }
2150  if(PlatAllowedFlag)
2151  {
2152  TrackLinkingRequiredFlag = true; // needed in order to call LinkTrack
2153  TrackPush(12, TempTrackElement);
2154  if(!CopyFlag) // don't need this for copy
2155  {
2156  SearchForAndUpdateLocationName(4, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2157  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2158  }
2159  // Must be called AFTER TrackPush
2160 // No need to plot the element - Clearand ... called after this function called
2161  // set corresponding track element length to 100m & give message if was different drop in v2.4.0
2162  // note can only be Length01 since even if points then only the straight part can be adjacent to the platform
2163 // drop in v2.4.0 if(TrackElementAt(907, VecPos).Length01 != DefaultTrackLength) ShowMessage("Note: The track element at this location has a length of " +
2164 // AnsiString(TrackElementAt(908, VecPos).Length01) + "m. It will be reset to 100m since all platform track lengths are fixed at 100m");
2165 // TrackElementAt(909, VecPos).Length01 = DefaultTrackLength;
2166  if(InternalChecks)
2167  {
2168  CheckMapAndInactiveTrack(12); // test
2169  CheckLocationNameMultiMap(20); // test
2170  }
2171  Utilities->CallLogPop(2064);
2172  return;
2173  }
2174  } // if(FoundFlag)
2175  Utilities->CallLogPop(2065);
2176  return;
2177  } // if platform
2178 
2179 // check if element is a LocationName - OK if placed on an allowable track element, or on a blank element
2180  if(TempTrackElement.TrackType == NamedNonStationLocation)
2181  {
2182  if((FoundFlag && (NameAllowed.Contains(TrackVector.at(VecPos).SpeedTag)) && !PlatformPresent && !InactiveFoundFlag) ||
2183  (!FoundFlag && !InactiveFoundFlag))
2184  // need to add && !NonStationOrLevelCrossingPresent, or better - !InactiveFoundFlag to above FoundFlag condition <-- OK done
2185  {
2186  TrackLinkingRequiredFlag = true; // needed in case have named a continuation, need to check if adjacent element named
2187  TrackPush(13, TempTrackElement);
2188  if(!CopyFlag) // don't need this for copy
2189  {
2190  SearchForAndUpdateLocationName(5, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2191  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2192  }
2193  if(VecPos > -1) // need to allow for non-station named locations that aren't on tracks
2194  {
2195 // drop in v2.4.0 if(TrackElementAt(910, VecPos).Length01 != DefaultTrackLength) ShowMessage("Note: The track element at this location has a length of " +
2196 // AnsiString(TrackElementAt(911, VecPos).Length01) + "m. It will be reset to 100m since all named location track lengths are fixed at 100m");
2197 // TrackElementAt(912, VecPos).Length01 = DefaultTrackLength; //NB named locations can only be placed at one track elements
2198  }
2199  if(InternalChecks)
2200  {
2201  CheckMapAndInactiveTrack(13); // test
2202  CheckLocationNameMultiMap(21); // test
2203  }
2204  Utilities->CallLogPop(2066);
2205  return;
2206  }
2207  else
2208  {
2209  Utilities->CallLogPop(2067);
2210  return;
2211  }
2212  }
2213 
2214 // check if a level crossing - OK if placed on a plain straight track
2215  if(TempTrackElement.TrackType == LevelCrossing)
2216  {
2217  if(FoundFlag && (LevelCrossingAllowed.Contains(TrackVector.at(VecPos).SpeedTag)) && !PlatformPresent && !InactiveFoundFlag)
2218  {
2219  TrackPush(14, TempTrackElement);
2220  PlotRaisedLinkedLevelCrossingBarriers(3, TrackVector.at(VecPos).SpeedTag, TempTrackElement.HLoc, TempTrackElement.VLoc, Display);
2221 // no need for reference to LC element as can't be open
2222  TrackLinkingRequiredFlag = true;
2223  Utilities->CallLogPop(2068);
2224  return;
2225  }
2226  else
2227  {
2228  Utilities->CallLogPop(2069);
2229  return; // was a level crossing but can't place it for some reason
2230  }
2231  }
2232 
2233 // check if another element already there
2234  else if(FoundFlag || InactiveFoundFlag)
2235  {
2236  Utilities->CallLogPop(2070);
2237  return; // something already there (active or inactive track)
2238  }
2239 
2240 // add LocationName if a FixedNamedLocationElement by checking for any adjacent names, then give all linked named location
2241 // elements the same name - in case had linked 2 separately named locations - all get the one name that it finds
2242 // first from an adjacent element search, also non-named location elements at platform locations have timetable name set
2243 // do this after pushed into vector so that can use EnterLocationName
2244 
2245  if(TempTrackElement.FixedNamedLocationElement) // concourse or footcrossing (platforms & named non-station locations already dealt with)
2246  {
2247  TrackPush(15, TempTrackElement);
2248  SearchForAndUpdateLocationName(6, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2249  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2250  }
2251  else if(TempTrackElement.TrackType == Points)
2252  {
2253  TrackPush(16, TempTrackElement);
2254  bool BothPointFillets = true;
2255  PlotPoints(7, TempTrackElement, Display, BothPointFillets);
2256  }
2257  else if(TempTrackElement.TrackType == SignalPost)
2258  {
2259  TrackPush(17, TempTrackElement);
2260  PlotSignal(14, TempTrackElement, Display);
2261  }
2262  else
2263  {
2264  TrackPush(18, TempTrackElement);
2265  TempTrackElement.PlotVariableTrackElement(6, Display); // all named locations already dealt with so no ambiguity between striped & non-striped
2266  }
2267  if((TempTrackElement.TrackType != Concourse) && (TempTrackElement.TrackType != Parapet))
2268  TrackLinkingRequiredFlag = true; // plats & NamedLocs aleady dealt with
2269  if(InternalChecks)
2270  {
2271  CheckMapAndTrack(12); // test
2272  CheckMapAndInactiveTrack(14); // test
2273  CheckLocationNameMultiMap(22); // test
2274  }
2275  Utilities->CallLogPop(2071);
2276 }
2277 
2278 // ---------------------------------------------------------------------------
2279 
2280 bool TTrack::TryToConnectTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool GiveMessages)
2281  // GiveMessages relates to the call to LinkTrack or LinkTrackNoMessages
2282  // return bool = true for success
2283  // LocError = true for location error & HLoc & VLoc to be inverted
2284 {
2285  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TryToConnectTrack," + AnsiString((short)GiveMessages));
2286  LocError = false;
2287  SetTrackFinished(false);
2288  if(TrackVector.size() == 0)
2289  {
2290  Utilities->CallLogPop(437);
2291  return false;
2292  }
2293  if(GapsUnset(7))
2294  {
2295  if(GiveMessages)
2296  ShowMessage("Gaps must be set before track can be validated");
2297  Utilities->CallLogPop(1135);
2298  return false;
2299  }
2300 // below sets all Conns and CLks to -1 except for gapjumps that match and are properly set,
2301 // returns true for any unset gaps
2303  {
2304  // can keep this exception as protected by the GapsUnset call above
2305  throw Exception("Error, gaps unset when TryToConnectTrack called");
2306  }
2308  CheckGapMap(1); // test
2309 // Gap connections now securely defined
2310 
2311  CheckMapAndTrack(8); // test
2312 
2313 // Perform a pre-check prior to TrackMap being compiled
2314  if(GiveMessages)
2315  {
2316  if(!LinkTrack(1, LocError, HLoc, VLoc, false))
2317  {
2318  Utilities->CallLogPop(439);
2319  return false;
2320  }
2321  }
2322  else
2323  {
2324  if(!LinkTrackNoMessages(1, false))
2325  {
2326  Utilities->CallLogPop(1131);
2327  return false;
2328  }
2329  }
2330 
2331 // here if pre-check successful
2332  if(!RepositionAndMapTrack(0))
2333  {
2334  ShowMessage("Error in RepositionAndMapTrack during TryToConnectTrack. Railway file is corrupt, further use may cause a system crash");
2335  Utilities->CallLogPop(1138);
2336  return false;
2337  }
2338 // now perform the final assembly - FinalCall = true
2339  if(GiveMessages)
2340  {
2341  if(!LinkTrack(2, LocError, HLoc, VLoc, true))
2342  {
2343  Utilities->CallLogPop(1116);
2344  return false;
2345  }
2346  }
2347  else
2348  {
2349  if(!LinkTrackNoMessages(2, true))
2350  {
2351  Utilities->CallLogPop(1132);
2352  return false;
2353  }
2354  }
2355 
2356 // success
2357 
2358  PopulateLCVector(0);
2359  CheckGapMap(2); // test
2360  CheckMapAndTrack(3); // test
2361  CheckMapAndInactiveTrack(3); // test
2362  CheckLocationNameMultiMap(9); // test
2363  SetTrackFinished(true);
2364 
2365 // Build ContinuationNameMap
2366  std::pair<AnsiString, char>TempMapPair;
2367 
2368  ContinuationNameMap.clear();
2369  for(int x = 0; x < Track->TrackVectorSize(); x++)
2370  {
2371  if((Track->TrackVector.at(x).TrackType == Continuation) && (Track->TrackVector.at(x).ActiveTrackElementName != ""))
2372  {
2373  TempMapPair.first = Track->TrackVector.at(x).ActiveTrackElementName;
2374  TempMapPair.second = 'x'; // unused
2375  ContinuationNameMap.insert(TempMapPair);
2376  }
2377  }
2378  Utilities->CallLogPop(440);
2379  return true;
2380 }
2381 
2382 // ---------------------------------------------------------------------------
2383 bool TTrack::ErrorInTrackBeforeSetGaps(int Caller, int &HLoc, int &VLoc)
2384  // unused - too time-consuming - double brute force search
2385 {
2386  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ErrorInTrackBeforeSetGaps");
2387  int NewHLoc, NewVLoc;
2388  bool ConnectionFoundFlag, LinkFoundFlag;
2389 
2390  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
2391  {
2392  for(unsigned int y = 0; y < 4; y++) // check all links for each element
2393  {
2394  if(TrackVector.at(x).Link[y] <= 0)
2395  continue; // no link
2396  if(TrackVector.at(x).Config[y] == End)
2397  continue; // buffer or continuation
2398  if(TrackVector.at(x).Config[y] == Gap)
2399  continue; // gap jump
2400  // get required H & V for track element joining link 'y'
2401  NewHLoc = TrackVector.at(x).HLoc + LinkHVArray[TrackVector.at(x).Link[y]][0];
2402  NewVLoc = TrackVector.at(x).VLoc + LinkHVArray[TrackVector.at(x).Link[y]][1];
2403  // find track element if present
2404  ConnectionFoundFlag = false;
2405  for(unsigned int z = 0; z < TrackVector.size(); z++)
2406  {
2407 // if(TrackElementAt(5, z).TrackType == Platform)
2408 // continue; //skip platforms
2409  if((TrackVector.at(z).HLoc == NewHLoc) && (TrackVector.at(z).VLoc == NewVLoc))
2410  {
2411  ConnectionFoundFlag = true;
2412  // find connecting link in the newly found track element if there is one
2413  LinkFoundFlag = false;
2414  for(unsigned int a = 0; a < 4; a++)
2415  {
2416  if(TrackVector.at(z).Link[a] == (10 - TrackVector.at(x).Link[y]))
2417  {
2418  LinkFoundFlag = true;
2419  }
2420  }
2421  // if there isn't a corresponding link set the invert values for the offending element
2422  if(!LinkFoundFlag)
2423  {
2424  HLoc = TrackVector.at(x).HLoc;
2425  VLoc = TrackVector.at(x).VLoc;
2426  Utilities->CallLogPop(441);
2427  return true;
2428  }
2429  break; // success, so break out of 'z' loop
2430  } // if((TrackVector.at(z).HLoc== NewHLoc) &&....
2431  } // for z...
2432  // if there isn't a connection set the invert values for the offending element
2433  if(!ConnectionFoundFlag)
2434  {
2435  HLoc = TrackVector.at(x).HLoc;
2436  VLoc = TrackVector.at(x).VLoc;
2437  Utilities->CallLogPop(442);
2438  return true;
2439  }
2440  } // for y....
2441  } // for x...
2442  Utilities->CallLogPop(443);
2443  return false; // all OK
2444 }
2445 
2446 // ---------------------------------------------------------------------------
2447 
2448 bool TTrack::FindNonPlatformMatch(int Caller, int HLoc, int VLoc, int &Position, TTrackElement &TrackElement) // true if find one
2449 {
2450  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindNonPlatformMatch," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
2451  TrackElement.LogTrack(0));
2452  bool FoundFlag;
2453 
2454  Position = GetVectorPositionFromTrackMap(13, HLoc, VLoc, FoundFlag);
2455  if(FoundFlag)
2456  TrackElement = TrackVector.at(Position);
2457  Utilities->CallLogPop(444);
2458  return FoundFlag;
2459 }
2460 
2461 // ---------------------------------------------------------------------------
2462 
2464 {
2465  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ReturnNextTrackElement");
2466  if(NextTrackElementPtr >= TrackVector.end())
2467  {
2468  Utilities->CallLogPop(1336);
2469  return false;
2470  }
2471  Next = *NextTrackElementPtr;
2473  Utilities->CallLogPop(1337);
2474  return true;
2475 }
2476 
2477 // ---------------------------------------------------------------------------
2478 
2480 {
2481  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ReturnNextInactiveTrackElement");
2483  {
2484  Utilities->CallLogPop(1338);
2485  return false;
2486  }
2487  Next = *NextTrackElementPtr;
2489  Utilities->CallLogPop(1339);
2490  return true;
2491 }
2492 
2493 // ---------------------------------------------------------------------------
2494 
2495 int TTrack::NumberOfGaps(int Caller)
2496 
2497 {
2498  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NumberOfGaps");
2499  int Count = 0;
2500 
2501  if(TrackVector.size() == 0)
2502  {
2503  Utilities->CallLogPop(1340);
2504  return 0;
2505  }
2506  for(unsigned int x = 0; x < TrackVector.size(); x++)
2507  {
2508  if(TrackVector.at(x).TrackType == GapJump)
2509  Count++;
2510  }
2511  Utilities->CallLogPop(1341);
2512  return Count;
2513 }
2514 
2515 // ---------------------------------------------------------------------------
2517  // above sets all Conns and CLks to -1 except for gapjumps that match and are properly set
2518  // returns true for any unset gaps
2519 {
2520  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetConnClkCheckUnsetGapJumps");
2521  bool UnsetGaps = false;
2522 
2523  if(TrackVector.size() == 0)
2524  {
2525  Utilities->CallLogPop(445);
2526  return false;
2527  }
2528  for(unsigned int x = 0; x < TrackVector.size(); x++)
2529  {
2530  if(TrackVector.at(x).TrackType != GapJump)
2531  {
2532  for(unsigned int y = 0; y < 4; y++)
2533  {
2534  TrackVector.at(x).Conn[y] = -1;
2535  TrackVector.at(x).ConnLinkPos[y] = -1;
2536  }
2537  }
2538  else // GapJump
2539  {
2540 // int tempint = TrackVector.at(x).Conn[0);
2541 
2542  if(TrackVector.at(x).Conn[0] == -1) // unset if -1
2543  {
2544  for(unsigned int y = 0; y < 4; y++)
2545  {
2546  TrackVector.at(x).Conn[y] = -1;
2547  TrackVector.at(x).ConnLinkPos[y] = -1;
2548  }
2549  UnsetGaps = true;
2550  continue; // to next 'x'
2551  }
2552  else // set, but may not have matching element, or that element may not be set
2553  {
2554  for(unsigned int y = 1; y < 4; y++) // reset the non-gap values anyway, gap always at position 0
2555  {
2556  TrackVector.at(x).Conn[y] = -1;
2557  TrackVector.at(x).ConnLinkPos[y] = -1;
2558  }
2559 
2560  if(TrackVector.at(TrackVector.at(x).Conn[0]).TrackType != GapJump)
2561  // check that the element pointed to by the gap link is a GapJump & if not clear Conns & CLks & reset Lk[0]
2562  {
2563  for(unsigned int y = 0; y < 4; y++)
2564  {
2565  TrackVector.at(x).Conn[y] = -1;
2566  TrackVector.at(x).ConnLinkPos[y] = -1;
2567  }
2568  UnsetGaps = true;
2569  continue; // to next 'x'
2570  }
2571 // here if gap connection is itself a GapJump
2572  if(TrackVector.at(TrackVector.at(x).Conn[0]).Conn[0] != (int)x)
2573  // check that the element pointed to by the gap link is a GapJump & that its gap link points back to 'x'
2574  // if not clear Conns & CLks & reset Lk[0]
2575  {
2576  for(unsigned int y = 0; y < 4; y++)
2577  {
2578  TrackVector.at(x).Conn[y] = -1;
2579  TrackVector.at(x).ConnLinkPos[y] = -1;
2580  }
2581  UnsetGaps = true;
2582  continue; // to next 'x'
2583  }
2584 // here if gap connection itself points back to 'x' so these two GapJumps match properly
2585 // hence no more action needed on these Conns & CLks
2586  }
2587  } // else //gap jump
2588  } // for x...
2589  Utilities->CallLogPop(446);
2590  return UnsetGaps;
2591 }
2592 
2593 // ---------------------------------------------------------------------------
2594 
2595 void TTrack::LoadTrack(int Caller, std::ifstream& VecFile, bool &GraphicsFollow)
2596 {
2597 // VecFile already open and its pointer at right place on calling
2598  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadTrack");
2599  int TempInt;
2600 
2601  TrackClear(1);
2602 // load track elements
2603  int NumberOfActiveElements = 0;
2604 
2605  GraphicsFollow = false;
2606  NumberOfActiveElements = Utilities->LoadFileInt(VecFile);
2607  AnsiString MarkerString = Utilities->LoadFileString(VecFile); // **Active elements** marker, if last character is '1' then there are graphics to be loaded
2608 
2609  if(MarkerString[MarkerString.Length()] == '1')
2610  {
2611  GraphicsFollow = true;
2612  }
2613  for(int x = 0; x < NumberOfActiveElements; x++)
2614  {
2615  VecFile >> TempInt; // TrackVectorNumber, not used
2616  VecFile >> TempInt; // SpeedTag
2617  TTrackElement TrackElement(FixedTrackArray.FixedTrackPiece[TempInt]);
2618  VecFile >> TempInt;
2619  TrackElement.HLoc = TempInt;
2620  VecFile >> TempInt;
2621  TrackElement.VLoc = TempInt;
2622  if(TrackElement.TrackType == GapJump)
2623  {
2624  VecFile >> TempInt;
2625  TrackElement.ConnLinkPos[0] = TempInt;
2626  VecFile >> TempInt;
2627  TrackElement.Conn[0] = TempInt;
2628  }
2629  if((TrackElement.TrackType == SignalPost) || (TrackElement.TrackType == Points))
2630  {
2631  VecFile >> TempInt;
2632  TrackElement.Attribute = TempInt;
2633  }
2634  if(TrackElement.TrackType == SignalPost)
2635  {
2636  VecFile >> TempInt;
2637  if(TempInt == 0)
2638  TrackElement.CallingOnSet = false;
2639  else
2640  TrackElement.CallingOnSet = true;
2641  }
2642  VecFile >> TempInt;
2643  TrackElement.Length01 = TempInt;
2644  VecFile >> TempInt;
2645  TrackElement.Length23 = TempInt;
2646  VecFile >> TempInt;
2647  if((TempInt != -1) && (TempInt < 10))
2648  TempInt = 10; // added at v0.6 to ensure old railway speed limits at least 10km/h
2649  if((TempInt != -1) && (TempInt > TTrain::MaximumSpeedLimit))
2650  TempInt = TTrain::MaximumSpeedLimit; // added at v2.1.0 to limit max speed
2651  TrackElement.SpeedLimit01 = TempInt;
2652  VecFile >> TempInt;
2653  if((TempInt != -1) && (TempInt < 10))
2654  TempInt = 10; // added at v0.6 to ensure old railway speed limits at least 10km/h
2655  if((TempInt != -1) && (TempInt > TTrain::MaximumSpeedLimit))
2656  TempInt = TTrain::MaximumSpeedLimit; // added at v2.1.0 to limit max speed
2657  TrackElement.SpeedLimit23 = TempInt;
2658 
2659  TrackElement.LocationName = Utilities->LoadFileString(VecFile);
2660  TrackElement.ActiveTrackElementName = Utilities->LoadFileString(VecFile);
2661  SetElementID(0, TrackElement);
2662  AnsiString Marker = Utilities->LoadFileString(VecFile); // marker
2663 // new for v0.6
2664  if(TrackElement.TrackType == SignalPost)
2665  {
2666  if(Marker[1] == '3')
2667  {
2668  TrackElement.SigAspect = TTrackElement::ThreeAspect;
2669  }
2670  else if(Marker[1] == '2')
2671  {
2672  TrackElement.SigAspect = TTrackElement::TwoAspect;
2673  }
2674  else if(Marker[1] == 'G')
2675  {
2676  TrackElement.SigAspect = TTrackElement::GroundSignal;
2677  }
2678  else
2679  {
2680  TrackElement.SigAspect = TTrackElement::FourAspect;
2681  }
2682  }
2683  if(TrackElement.SpeedTag != 0)
2684  TrackPush(8, TrackElement); // don't save default elements (now dispensed with)
2685  }
2686  int NumberOfInactiveElements = 0;
2687 
2688  NumberOfInactiveElements = Utilities->LoadFileInt(VecFile);
2689  Utilities->LoadFileString(VecFile); // **Inactive elements** marker
2690  for(int x = 0; x < NumberOfInactiveElements; x++)
2691  {
2692  VecFile >> TempInt; // InactiveTrackVectorNumber - not used, only used for identification in file
2693  VecFile >> TempInt; // SpeedTag
2694  TTrackElement TrackElement(FixedTrackArray.FixedTrackPiece[TempInt]);
2695  VecFile >> TempInt;
2696  TrackElement.HLoc = TempInt;
2697  VecFile >> TempInt;
2698  TrackElement.VLoc = TempInt;
2699  TrackElement.LocationName = Utilities->LoadFileString(VecFile);
2700  SetElementID(3, TrackElement);
2701  TrackPush(9, TrackElement);
2702  Utilities->LoadFileString(VecFile); // marker
2703  }
2704  bool LocError = false; // needed for TryToConnectTrack but not used
2705  int H = -1, V = -1; // needed for TryToConnectTrack but not used
2706 
2707  if(TryToConnectTrack(2, LocError, H, V, false)) // false for don't give messages
2708  {
2709  SetTrackFinished(true);
2710  }
2711  else
2712  {
2713  SetTrackFinished(false);
2714  }
2715 // CheckMapAndTrack(9); all these checked in TryToConnectTrack
2716 // CheckMapAndInactiveTrack(8);
2717 // CheckLocationNameMultiMap(10);
2718  Utilities->CallLogPop(448);
2719 }
2720 
2721 // ---------------------------------------------------------------------------
2722 
2723 void TTrack::LoadGraphics(int Caller, std::ifstream &VecFile, UnicodeString GraphicsPath)
2724 {
2725 // VecFile already open and its pointer at right place on calling
2726  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadGraphics, " + GraphicsPath);
2727 // first int is number og graphics, then each graphic, create in UserGraphicMap, derive Width & height from TPicture
2728 // & load into UserGraphicItem then store in UserGraphicVector
2729  UserGraphicVector.clear();
2730  TUserGraphicItem UGI;
2731  int NumberOfGraphics = Utilities->LoadFileInt(VecFile);
2732 
2733  for(int x = 0; x < NumberOfGraphics; x++)
2734  {
2735  UGI.FileName = GraphicsPath + "\\" + Utilities->LoadFileString(VecFile);
2736  UGI.HPos = Utilities->LoadFileInt(VecFile);
2737  UGI.VPos = Utilities->LoadFileInt(VecFile);
2738  UGI.Width = 0; // provisional value
2739  UGI.Height = 0; // provisional value
2740  UGI.UserGraphic = NULL; // provisional value
2741  UserGraphicVector.push_back(UGI);
2742  }
2743 // now load the map & set Width, Height & TPicture*
2744  bool FileError = false;
2745 
2746  for(int x = 0; x < NumberOfGraphics; x++)
2747  {
2748  if(FileError)
2749  {
2750  break; // otherwise keeps going round the loop
2751  }
2752  UGI = UserGraphicVectorAt(0, x);
2753  if(UserGraphicMap.empty()) // will be when x == 0 but not after
2754  {
2755  try
2756  {
2757 // TUserGraphicMapEntry UGME; //can't define it here, it has to be defined before it is used - now defined in TrackUnit.h
2758  UGME.first = UGI.FileName;
2759  UGME.second = new TPicture;
2760  UGME.second->LoadFromFile(UGME.first); // errors caught below
2761  if(!Track->UserGraphicMap.insert(UGME).second) // if no failure then the new entry is inserted
2762  {
2763  throw Exception("Map Insertion Error 2 - UserGraphicMap insertion failure for " + UGI.FileName);
2764  }
2765  UGI.UserGraphic = UGME.second;
2766  UGI.Width = UGI.UserGraphic->Width;
2767  UGI.Height = UGI.UserGraphic->Height;
2768  UserGraphicVectorAt(1, x) = UGI;
2769  }
2770  catch(const EInvalidGraphic &e)
2771  {
2772  ShowMessage(UGI.FileName +
2773  " has an incorrect file format, graphics can't be loaded. Ensure that all graphic files are valid with extension .bmp, .gif, .jpg, or .png");
2774  FileError = true;
2775  UserGraphicVector.clear(); // so doesn't try to plot non-existent graphics
2776  if(!UserGraphicMap.empty())
2777  {
2778  for(TTrack::TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
2779  {
2780  delete UGMIt->second;
2781  }
2782  UserGraphicMap.clear();
2783  }
2784  }
2785  catch(const Exception &e)
2786  {
2787  ShowMessage("Unable to load file, ensure that this graphic file exists: " + UGI.FileName +
2788  ", and that it is has extension .bmp, .gif, .jpg, or .png. Graphics can't be loaded.");
2789  FileError = true;
2790  UserGraphicVector.clear(); // so doesn't try to plot non-existent graphics
2791  if(!UserGraphicMap.empty())
2792  {
2793  for(TTrack::TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
2794  {
2795  delete UGMIt->second;
2796  }
2797  UserGraphicMap.clear();
2798  }
2799  }
2800  }
2801  else
2802  {
2803  bool FoundInMap = false;
2804  for(TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
2805  {
2806  if(UGI.FileName == UGMIt->first) // already exists in map
2807  {
2808  UGI.UserGraphic = UGMIt->second;
2809  UGI.Width = UGI.UserGraphic->Width;
2810  UGI.Height = UGI.UserGraphic->Height;
2811  UserGraphicVectorAt(2, x) = UGI;
2812  FoundInMap = true;
2813  break;
2814  }
2815  }
2816  if(!FoundInMap)
2817  {
2818  try
2819  {
2821  UGME.first = UGI.FileName;
2822  UGME.second = new TPicture;
2823  UGME.second->LoadFromFile(UGME.first); // errors caught below
2824  if(!Track->UserGraphicMap.insert(UGME).second) // if no failure then the new entry is inserted
2825  {
2826  throw Exception("Map Insertion Error 3 - UserGraphicMap insertion failure for " + UGI.FileName);
2827  }
2828  UGI.UserGraphic = UGME.second;
2829  UGI.Width = UGI.UserGraphic->Width;
2830  UGI.Height = UGI.UserGraphic->Height;
2831  UserGraphicVectorAt(3, x) = UGI;
2832  }
2833  catch(const EInvalidGraphic &e)
2834  {
2835  ShowMessage(UGI.FileName +
2836  " has an incorrect file format, graphics can't be loaded. Ensure that all graphic files are valid with extension .bmp, .gif, .jpg, or .png");
2837  FileError = true;
2838  UserGraphicVector.clear(); // so doesn't try to plot non-existent graphics
2839  if(!UserGraphicMap.empty())
2840  {
2841  for(TTrack::TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
2842  {
2843  delete UGMIt->second;
2844  }
2845  UserGraphicMap.clear();
2846  }
2847  }
2848  catch(const Exception &e)
2849  {
2850  ShowMessage("Unable to load file, ensure that this graphic file exists: " + UGI.FileName +
2851  ", and that it is has extension .bmp, .gif, .jpg, or .png");
2852  FileError = true;
2853  UserGraphicVector.clear(); // so doesn't try to plot non-existent graphics
2854  if(!UserGraphicMap.empty())
2855  {
2856  for(TTrack::TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
2857  {
2858  delete UGMIt->second;
2859  }
2860  UserGraphicMap.clear();
2861  }
2862  }
2863  }
2864  }
2865  }
2866  Utilities->CallLogPop(2167);
2867 }
2868 
2869 // ---------------------------------------------------------------------------
2870 
2871 void TTrack::SaveTrack(int Caller, std::ofstream& VecFile, bool GraphicsFollow)
2872 {
2873 // VecFile already open and its pointer at right place on calling
2874 // if GraphicsFollow true, then save Marker as **Active elements**1
2875 // save trackfinished flag
2876  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveTrack, " + AnsiString(int(GraphicsFollow)));
2877  TTrackElement TrackElement, InactiveTrackElement;
2878 
2879 // save track elements
2880  Utilities->SaveFileInt(VecFile, TrackVector.size());
2881  if(GraphicsFollow)
2882  {
2883  VecFile << "**Active elements**1" << '\0' << '\n';
2884  }
2885  else
2886  {
2887  VecFile << "**Active elements**" << '\0' << '\n';
2888  }
2889  for(unsigned int x = 0; x < (TrackVector.size()); x++)
2890  {
2891  TrackElement = TrackVector.at(x);
2892  VecFile << x << '\n'; // this is the TrackVectorNumber - extra, so easier to identify in the file
2893  VecFile << TrackElement.SpeedTag << '\n';
2894  VecFile << TrackElement.HLoc << '\n';
2895  VecFile << TrackElement.VLoc << '\n';
2896  if(TrackElement.TrackType == GapJump)
2897  {
2898  VecFile << TrackElement.ConnLinkPos[0] << '\n';
2899  VecFile << TrackElement.Conn[0] << '\n';
2900  }
2901  if((TrackElement.TrackType == SignalPost) || (TrackElement.TrackType == Points))
2902  {
2903  VecFile << TrackElement.Attribute << '\n';
2904  }
2905  if(TrackElement.TrackType == SignalPost)
2906  {
2907  if(TrackElement.CallingOnSet)
2908  VecFile << int(1) << '\n';
2909  else
2910  VecFile << int(0) << '\n';
2911  }
2912  VecFile << TrackElement.Length01 << '\n';
2913  VecFile << TrackElement.Length23 << '\n';
2914  VecFile << TrackElement.SpeedLimit01 << '\n';
2915  VecFile << TrackElement.SpeedLimit23 << '\n';
2916  VecFile << TrackElement.LocationName.c_str() << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
2917  VecFile << TrackElement.ActiveTrackElementName.c_str() << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
2918 // new for v0.6
2919  if(TrackElement.TrackType == SignalPost)
2920  {
2921  if(TrackElement.SigAspect == TTrackElement::ThreeAspect)
2922  {
2923  VecFile << "3*****" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
2924  }
2925  else if(TrackElement.SigAspect == TTrackElement::TwoAspect)
2926  {
2927  VecFile << "2*****" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
2928  }
2929  else if(TrackElement.SigAspect == TTrackElement::GroundSignal)
2930  {
2931  VecFile << "G*****" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
2932  }
2933  else // 4 aspect
2934  {
2935  VecFile << "4*****" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
2936  }
2937  }
2938  else
2939  {
2940  VecFile << "******" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
2941  }
2942  }
2943 
2944  Utilities->SaveFileInt(VecFile, InactiveTrackVector.size());
2945  VecFile << "**Inactive elements**" << '\0' << '\n'; // extra
2946  for(unsigned int x = 0; x < (InactiveTrackVector.size()); x++)
2947  {
2948  InactiveTrackElement = InactiveTrackVector.at(x);
2949  VecFile << x << '\n'; // this is the Inactive TrackVectorNumber - extra
2950  VecFile << InactiveTrackElement.SpeedTag << '\n';
2951  VecFile << InactiveTrackElement.HLoc << '\n';
2952  VecFile << InactiveTrackElement.VLoc << '\n';
2953  VecFile << InactiveTrackElement.LocationName.c_str() << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
2954  VecFile << "******" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
2955  }
2956  Utilities->CallLogPop(449);
2957 }
2958 
2959 // ---------------------------------------------------------------------------
2960 
2961 bool TTrack::CheckTrackElementsInFile(int Caller, int &NumberOfActiveElements, bool &GraphicsFollow, std::ifstream& VecFile)
2962 {
2963 // VecFile already open and its pointer at right place on calling
2964 // check trackfinished flag
2965 // inactive elements follow immediately after active elements, no need to check for a marker between them
2966  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckTrackElementsInFile");
2967  int TempInt;
2968 
2969  GraphicsFollow = false;
2970  NumberOfActiveElements = Utilities->LoadFileInt(VecFile);
2971  if((NumberOfActiveElements < 0) || (NumberOfActiveElements > 1000000)) // No of active elements (up to 500 screens all completely full!)
2972  {
2973  Utilities->CallLogPop(1513);
2974  return false;
2975  }
2976 // if(!Utilities->CheckAndCompareFileString(VecFile, "**Active elements**")) dropped at v2.4.0 as could have a '1' at the end if there are graphics
2977  AnsiString MarkerString;
2978 
2979  if(!Utilities->CheckAndReadFileString(VecFile, MarkerString)) // new version for v2.4.0
2980  {
2981  Utilities->CallLogPop(1758);
2982  return false;
2983  }
2984  if(MarkerString[MarkerString.Length()] == '1')
2985  {
2986  GraphicsFollow = true;
2987  }
2988  for(int x = 0; x < NumberOfActiveElements; x++)
2989  {
2990  if(!Utilities->CheckFileInt(VecFile, x, x)) // TrackVectorNumber, must be 'x'
2991  {
2992  Utilities->CallLogPop(1759);
2993  return false;
2994  }
2995  VecFile >> TempInt;
2996  int SpeedTag = TempInt;
2997  if((TempInt < 0) || (TempInt >= FirstUnusedSpeedTagNumber) || (TempInt == 17)) // Speedtag
2998  {
2999  Utilities->CallLogPop(1514);
3000  return false;
3001  }
3002  VecFile >> TempInt;
3003  if(((TempInt > 999999) || (TempInt < -1000001)) && (TempInt != -2000000000)) // HLoc
3004  {
3005  Utilities->CallLogPop(1495);
3006  return false;
3007  }
3008  VecFile >> TempInt;
3009  if(((TempInt > 999999) || (TempInt < -1000001)) && (TempInt != -2000000000)) // VLoc
3010  {
3011  Utilities->CallLogPop(1497);
3012  return false;
3013  }
3014  if((SpeedTag > 87) && (SpeedTag < 96)) // GapJumps 88-95 incl
3015  {
3016  VecFile >> TempInt;
3017  if((TempInt < -1) || (TempInt > 3)) // ConnLinkPos[0]
3018  {
3019  Utilities->CallLogPop(1499);
3020  return false;
3021  }
3022  VecFile >> TempInt;
3023  if((TempInt < -1) || (TempInt > 999999)) // Conn[0]
3024  {
3025  Utilities->CallLogPop(1500);
3026  return false;
3027  }
3028  }
3029  if(((SpeedTag >= 7) && (SpeedTag <= 14)) || ((SpeedTag >= 28) && (SpeedTag <= 43)) || ((SpeedTag >= 132) && (SpeedTag <= 139)) ||
3030  ((SpeedTag >= 68) && (SpeedTag <= 75)))
3031  {
3032  VecFile >> TempInt;
3033  if((TempInt < -1) || (TempInt > 5)) // Points & signal attribute
3034  {
3035  Utilities->CallLogPop(1502);
3036  return false;
3037  }
3038  }
3039  if((SpeedTag >= 68) && (SpeedTag <= 75)) // signals
3040  {
3041  VecFile >> TempInt;
3042  if((TempInt != 0) && (TempInt != 1)) // CallingOnSet
3043  {
3044  Utilities->CallLogPop(1155);
3045  return false;
3046  }
3047  }
3048  VecFile >> TempInt;
3049  if((TempInt < -1) || (TempInt > 999999)) // Length01
3050  {
3051  Utilities->CallLogPop(1503);
3052  return false;
3053  }
3054  VecFile >> TempInt;
3055  if((TempInt < -1) || (TempInt > 999999)) // Length23
3056  {
3057  Utilities->CallLogPop(1504);
3058  return false;
3059  }
3060  VecFile >> TempInt;
3061  if((TempInt < -1) || (TempInt > 999999)) // SpeedLimit01
3062  {
3063  Utilities->CallLogPop(1505);
3064  return false;
3065  }
3066  VecFile >> TempInt;
3067  if((TempInt < -1) || (TempInt > 999999)) // SpeedLimit23
3068  {
3069  Utilities->CallLogPop(1506);
3070  return false;
3071  }
3072  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3073  {
3074  Utilities->CallLogPop(1142);
3075  return false; // LocationName
3076  }
3077  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3078  {
3079  Utilities->CallLogPop(1143);
3080  return false; // ActiveTrackElementName
3081  }
3082  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3083  {
3084  Utilities->CallLogPop(1787);
3085  return false; // marker
3086  }
3087  }
3088  int NumberOfInactiveElements = 0;
3089 
3090  NumberOfInactiveElements = Utilities->LoadFileInt(VecFile);
3091  if(NumberOfInactiveElements < 0) // No of active elements
3092  {
3093  Utilities->CallLogPop(1493);
3094  return false;
3095  }
3096  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3097  {
3098  Utilities->CallLogPop(1764);
3099  return false; // **Inactive elements** marker
3100  }
3101  for(int x = 0; x < NumberOfInactiveElements; x++)
3102  {
3103  if(!Utilities->CheckFileInt(VecFile, x, x)) // TrackVectorNumber, must be 'x'
3104  {
3105  Utilities->CallLogPop(1765);
3106  return false;
3107  }
3108  VecFile >> TempInt;
3109  if((TempInt < 0) || (TempInt >= FirstUnusedSpeedTagNumber) || (TempInt == 17)) // Speedtag
3110  {
3111  Utilities->CallLogPop(1494);
3112  return false;
3113  }
3114  VecFile >> TempInt;
3115  if(((TempInt > 999999) || (TempInt < -1000001)) && (TempInt != -2000000000)) // HLoc
3116  {
3117  Utilities->CallLogPop(1496);
3118  return false;
3119  }
3120  VecFile >> TempInt;
3121  if(((TempInt > 999999) || (TempInt < -1000001)) && (TempInt != -2000000000)) // VLoc
3122  {
3123  Utilities->CallLogPop(1498);
3124  return false;
3125  }
3126  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3127  {
3128  Utilities->CallLogPop(1144);
3129  return false; // LocationName
3130  }
3131  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3132  {
3133  Utilities->CallLogPop(1788);
3134  return false; // marker
3135  }
3136  }
3137  Utilities->CallLogPop(1507);
3138  return true;
3139 }
3140 
3141 // ---------------------------------------------------------------------------
3142 
3143 bool TTrack::CheckUserGraphics(int Caller, std::ifstream &VecFile, UnicodeString GraphicsPath)
3144 {
3145  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckUserGraphics");
3146  int NumberOfGraphics = Utilities->LoadFileInt(VecFile);
3147 
3148  if((NumberOfGraphics < 0) || (NumberOfGraphics > 100000)) // 100,000 should be plenty!
3149  {
3150  Utilities->CallLogPop(2168);
3151  return false;
3152  }
3153  // filename in Graphics folder, then HPos, then VPos
3154  AnsiString FileName;
3155 
3156  for(int x = 0; x < NumberOfGraphics; x++)
3157  {
3158  TPicture *TempPicture = new TPicture;
3159  try
3160  {
3161  if(!Utilities->CheckAndReadFileString(VecFile, FileName))
3162  {
3163  Utilities->CallLogPop(2169);
3164  return false;
3165  }
3166  TempPicture->LoadFromFile(GraphicsPath + "\\" + FileName); // only loaded to check and catch errors
3167  delete TempPicture;
3168  if(!Utilities->CheckFileInt(VecFile, -2000000, 2000000)) // HPos, allow plenty of scope
3169  {
3170  Utilities->CallLogPop(2170);
3171  return false;
3172  }
3173  if(!Utilities->CheckFileInt(VecFile, -2000000, 2000000)) // VPos
3174  {
3175  Utilities->CallLogPop(2171);
3176  return false;
3177  }
3178  }
3179  catch(const EInvalidGraphic &e)
3180  {
3181  ShowMessage(FileName +
3182  " has an incorrect file format, graphics can't be loaded. Ensure that all graphic files are valid with extension .bmp, .gif, .jpg, or .png");
3183  delete TempPicture;
3184  Utilities->CallLogPop(2172);
3185  return false;
3186  }
3187  catch(const Exception &e)
3188  {
3189  ShowMessage("Unable to load file, ensure that " + FileName +
3190  " exists in the 'Graphics' folder and that it is has extension .bmp, .gif, .jpg, or .png.");
3191  delete TempPicture;
3192  Utilities->CallLogPop(2173);
3193  return false;
3194  }
3195  }
3196  Utilities->CallLogPop(2174);
3197  return true;
3198 }
3199 
3200 // ---------------------------------------------------------------------------
3201 
3202 void TTrack::SaveSessionBarriersDownVector(int Caller, std::ofstream &OutFile)
3203 {
3204  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveSessionBarriersDownVector");
3205  int VecSize = Track->BarriersDownVector.size();
3206 
3207  Utilities->SaveFileInt(OutFile, VecSize);
3208  for(int x = 0; x < VecSize; x++)
3209  {
3211  Utilities->SaveFileBool(OutFile, TALC.ConsecSignals);
3212  Utilities->SaveFileBool(OutFile, TALC.TrainPassed);
3213  Utilities->SaveFileInt(OutFile, (short)TALC.BarrierState);
3214  Utilities->SaveFileDouble(OutFile, TALC.ChangeDuration);
3215  Utilities->SaveFileInt(OutFile, TALC.BaseElementSpeedTag);
3216  Utilities->SaveFileInt(OutFile, TALC.HLoc);
3217  Utilities->SaveFileInt(OutFile, TALC.VLoc);
3218  Utilities->SaveFileDouble(OutFile, double(TALC.StartTime));
3219  }
3220  Utilities->CallLogPop(1963);
3221 }
3222 
3223 // ---------------------------------------------------------------------------
3224 
3225 void TTrack::SaveChangingLCVector(int Caller, std::ofstream &OutFile)
3226 {
3227  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveChangingLCVector");
3228  int VecSize = Track->ChangingLCVector.size();
3229 
3230  Utilities->SaveFileInt(OutFile, VecSize);
3231  for(int x = 0; x < VecSize; x++)
3232  {
3234  Utilities->SaveFileBool(OutFile, TALC.ConsecSignals);
3235  Utilities->SaveFileBool(OutFile, TALC.TrainPassed);
3236  Utilities->SaveFileInt(OutFile, (short)TALC.BarrierState);
3237  Utilities->SaveFileDouble(OutFile, TALC.ChangeDuration);
3238  Utilities->SaveFileInt(OutFile, TALC.BaseElementSpeedTag);
3239  Utilities->SaveFileInt(OutFile, TALC.HLoc);
3240  Utilities->SaveFileInt(OutFile, TALC.VLoc);
3241  Utilities->SaveFileDouble(OutFile, double(TALC.StartTime));
3242  }
3243  Utilities->CallLogPop(1980);
3244 }
3245 
3246 // ---------------------------------------------------------------------------
3247 
3248 bool TTrack::CheckActiveLCVector(int Caller, std::ifstream &VecFile)
3249 {
3250  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckActiveLCVector");
3251  int VecSize = Utilities->LoadFileInt(VecFile);
3252 
3253  for(int x = 0; x < VecSize; x++)
3254  {
3255  if(!Utilities->CheckFileBool(VecFile))
3256  {
3257  Utilities->CallLogPop(1970);
3258  return false;
3259  }
3260  if(!Utilities->CheckFileBool(VecFile))
3261  {
3262  Utilities->CallLogPop(1971);
3263  return false;
3264  }
3265  if(!Utilities->CheckFileInt(VecFile, 0, 3))
3266  {
3267  Utilities->CallLogPop(1972);
3268  return false;
3269  }
3270  if(!Utilities->CheckFileDouble(VecFile))
3271  {
3272  Utilities->CallLogPop(1973);
3273  return false;
3274  }
3275  if(!Utilities->CheckFileInt(VecFile, 1, 2))
3276  {
3277  Utilities->CallLogPop(1974);
3278  return false;
3279  }
3280  if(!Utilities->CheckFileInt(VecFile, -1000001, 999999))
3281  {
3282  Utilities->CallLogPop(1975);
3283  return false;
3284  }
3285  if(!Utilities->CheckFileInt(VecFile, -1000001, 999999))
3286  {
3287  Utilities->CallLogPop(1976);
3288  return false;
3289  }
3290  if(!Utilities->CheckFileDouble(VecFile))
3291  {
3292  Utilities->CallLogPop(1977);
3293  return false;
3294  }
3295  }
3296  Utilities->CallLogPop(1978);
3297  return true;
3298 }
3299 
3300 // ---------------------------------------------------------------------------
3301 
3302 void TTrack::LoadBarriersDownVector(int Caller, std::ifstream &VecFile)
3303 {
3304  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadBarriersDownVector");
3305  int VecSize = Utilities->LoadFileInt(VecFile);
3306 
3307  for(int x = 0; x < VecSize; x++)
3308  {
3309  TActiveLevelCrossing TALC;
3310  TALC.ConsecSignals = Utilities->LoadFileBool(VecFile);
3311  TALC.TrainPassed = Utilities->LoadFileBool(VecFile);
3312  TALC.BarrierState = TBarrierState(Utilities->LoadFileInt(VecFile));
3313  TALC.ChangeDuration = Utilities->LoadFileDouble(VecFile);
3314  TALC.BaseElementSpeedTag = Utilities->LoadFileInt(VecFile);
3315  TALC.HLoc = Utilities->LoadFileInt(VecFile);
3316  TALC.VLoc = Utilities->LoadFileInt(VecFile);
3317  TALC.StartTime = TDateTime(Utilities->LoadFileDouble(VecFile));
3318  BarriersDownVector.push_back(TALC);
3319  }
3320  Utilities->CallLogPop(1979);
3321 }
3322 
3323 // ---------------------------------------------------------------------------
3324 
3325 void TTrack::RebuildTrackAndText(int Caller, TDisplay *Disp, bool BothPointFilletsAndBasicLCs)
3326 /*
3327  Note, have to plot inactives before track because track has to overwrite NamedNonStationLocations, but, plot basic LC's (if flag set) after track
3328  so they lie above the track. Basic LCs are plotted for all but Level1Mode == OperMode (i.e. closed to trains), because the LC attributes will always be
3329  0 in such cases and because in OperMode the LCs have to be plotted again after the routes, which is done in Clearand....
3330 */
3331 {
3332  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RebuildTrackAndText," + AnsiString((short)BothPointFilletsAndBasicLCs));
3333  TTrackElement Next;
3334 
3335 // Disp->ClearDisplay();
3337  while(ReturnNextInactiveTrackElement(0, Next))
3338  {
3339  if(Next.TrackType != LevelCrossing) // don't plot level crossings as these need to be plotted after the track
3340  {
3341  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3342  {
3343  // only plot if on screen, to save time
3344  if(((Next.HLoc - Display->DisplayOffsetH) >= 0) && ((Next.HLoc - Display->DisplayOffsetH) < Utilities->ScreenElementWidth) &&
3346  {
3347  Next.PlotVariableTrackElement(2, Disp); // striped if not named
3348  }
3349  }
3350  }
3351  }
3352 
3353  TextHandler->RebuildFromTextVector(1, Disp); // plot text after inactives so can have text on stations etc
3354 
3355  NextTrackElementPtr = TrackVector.begin();
3356  while(ReturnNextTrackElement(0, Next))
3357  {
3358  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3359  {
3360  if(((Next.HLoc - Display->DisplayOffsetH) >= 0) && ((Next.HLoc - Display->DisplayOffsetH) < Utilities->ScreenElementWidth) &&
3362  {
3363  if(Next.TrackType == Points)
3364  PlotPoints(5, Next, Disp, BothPointFilletsAndBasicLCs);
3365  else if(Next.TrackType == SignalPost)
3366  PlotSignal(9, Next, Disp);
3367  else if(Next.TrackType == GapJump)
3368  PlotGap(0, Next, Disp);
3369  else
3370  Next.PlotVariableTrackElement(3, Disp); // for footcrossings, may be striped or not
3371  }
3372  }
3373  }
3374 
3375  if(BothPointFilletsAndBasicLCs)
3376  {
3378  while(ReturnNextInactiveTrackElement(4, Next))
3379  {
3380  if(Next.TrackType == LevelCrossing) // plot level crossings (if required) after the track
3381  {
3382  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3383  {
3384  // only plot if on screen, to save time, & OK as plotting one by one here
3385  if(((Next.HLoc - Display->DisplayOffsetH) >= 0) && ((Next.HLoc - Display->DisplayOffsetH) < Utilities->ScreenElementWidth) &&
3387  {
3388  if(GetTrackElementFromTrackMap(1, Next.HLoc, Next.VLoc).SpeedTag == 1)
3389  {
3390  Disp->PlotOutput(193, (Next.HLoc * 16), (Next.VLoc * 16), RailGraphics->LCBothVer);
3391  }
3392  else
3393  {
3394  Disp->PlotOutput(194, (Next.HLoc * 16), (Next.VLoc * 16), RailGraphics->LCBothHor);
3395  }
3396  }
3397  }
3398  }
3399  }
3400  }
3401  Disp->Update();
3402  Utilities->CallLogPop(468);
3403 }
3404 
3405 // ---------------------------------------------------------------------------
3406 
3407 void TTrack::RebuildUserGraphics(int Caller, TDisplay *Disp) // new at v2.4.0
3408 {
3409  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RebuildUserGraphics,");
3410  if(UserGraphicVector.empty())
3411  {
3412  Utilities->CallLogPop(2175);
3413  return;
3414  }
3415  TUserGraphicItem UGI;
3416 
3417  for(unsigned int x = 0; x < UserGraphicVector.size(); x++)
3418  {
3419  UGI = UserGraphicVectorAt(4, x);
3420  if(((UGI.HPos + UGI.Width - (Display->DisplayOffsetH * 16)) >= 0) && ((UGI.HPos - (Display->DisplayOffsetH * 16)) <
3421  (Utilities->ScreenElementWidth * 16)) && ((UGI.VPos + UGI.Height - (Display->DisplayOffsetV * 16)) >= 0) &&
3422  ((UGI.VPos - (Display->DisplayOffsetV * 16)) < (Utilities->ScreenElementHeight * 16)))
3423  {
3424  Disp->PlotAndAddUserGraphic(0, UGI);
3425  }
3426  }
3427  Disp->Update();
3428  Utilities->CallLogPop(2176);
3429 }
3430 
3431 // ---------------------------------------------------------------------------
3432 
3433 void TTrack::WriteTrackToImage(int Caller, Graphics::TBitmap *Bitmap)
3434 /*
3435  Note, have to plot inactives before track because track has to overwrite 'name' platforms (NamedLocationElements)
3436 */
3437 {
3438  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WriteTrackToImage");
3439 // need to change graphics back to black on white if have a dark background
3440  TColor OldTransparentColour = Utilities->clTransparent;
3441 
3443  {
3444  Utilities->clTransparent = TColor(0xFFFFFF); // white
3447  }
3448  TTrackElement Next;
3449 
3450  Bitmap->Canvas->CopyMode = cmSrcCopy;
3452  Graphics::TBitmap *GraphicOutput;
3453 
3454  while(ReturnNextInactiveTrackElement(2, Next))
3455  {
3456  GraphicOutput = Next.GraphicPtr;
3457  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3458  {
3459  if(Next.LocationName == "") // plot as named or unnamed (striped)
3460  { // default is not striped
3461  switch(Next.SpeedTag)
3462  {
3463  case 76: // t platform
3464  GraphicOutput = RailGraphics->gl76Striped;
3465  break;
3466 
3467  case 77: // h platform
3468  GraphicOutput = RailGraphics->bm77Striped;
3469  break;
3470 
3471  case 78: // v platform
3472  GraphicOutput = RailGraphics->bm78Striped;
3473  break;
3474 
3475  case 79: // r platform
3476  GraphicOutput = RailGraphics->gl79Striped;
3477  break;
3478 
3479  case 96: // concourse
3480  GraphicOutput = RailGraphics->ConcourseStriped;
3481  break;
3482 
3483  case 129: // v footbridge
3484  GraphicOutput = RailGraphics->gl129Striped;
3485  break;
3486 
3487  case 130: // h footbridge
3488  GraphicOutput = RailGraphics->gl130Striped;
3489  break;
3490 
3491  case 131: // non-station named loc
3492  GraphicOutput = RailGraphics->bmNameStriped;
3493  break;
3494 
3495  case 145: // v underpass
3496  GraphicOutput = RailGraphics->gl145Striped;
3497  break;
3498 
3499  case 146: // h underpass
3500  GraphicOutput = RailGraphics->gl146Striped;
3501  break;
3502 
3503  default:
3504  GraphicOutput = Next.GraphicPtr;
3505  break;
3506  }
3507  }
3508  if(Next.SpeedTag == 144) // level crossing
3509  {
3510  if(GetTrackElementFromTrackMap(2, Next.HLoc, Next.VLoc).SpeedTag == 1)
3511  {
3512  GraphicOutput = RailGraphics->LCBothVer;
3513  }
3514  else
3515  {
3516  GraphicOutput = RailGraphics->LCBothHor;
3517  }
3518  }
3519  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), GraphicOutput);
3520  }
3521  }
3522 
3523  NextTrackElementPtr = TrackVector.begin();
3524  while(ReturnNextTrackElement(2, Next))
3525  {
3526  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3527  {
3528  if(Next.TrackType == Points) // plot both fillets
3529  {
3530  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), Next.GraphicPtr);
3531  if(Next.SpeedTag < 28)
3532  {
3533  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3535  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3537  }
3538  else if(Next.SpeedTag < 132)
3539  {
3540  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3541  RailGraphics->PointModeGraphicsPtr[Next.SpeedTag - 20][0]);
3542  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3543  RailGraphics->PointModeGraphicsPtr[Next.SpeedTag - 20][1]);
3544  }
3545  else
3546  {
3547  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3548  RailGraphics->PointModeGraphicsPtr[Next.SpeedTag - 108][0]);
3549  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3550  RailGraphics->PointModeGraphicsPtr[Next.SpeedTag - 108][1]);
3551  }
3552  }
3553  else if(Next.TrackType == GapJump) // plot as connected or unconnected
3554  {
3555  if((Next.SpeedTag == 88) && (Next.Conn[0] > -1))
3556  {
3557  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl88set);
3558  }
3559  else if((Next.SpeedTag == 88) && (Next.Conn[0] == -1))
3560  {
3561  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl88unset);
3562  }
3563  if((Next.SpeedTag == 89) && (Next.Conn[0] > -1))
3564  {
3565  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl89set);
3566  }
3567  else if((Next.SpeedTag == 89) && (Next.Conn[0] == -1))
3568  {
3569  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl89unset);
3570  }
3571  if((Next.SpeedTag == 90) && (Next.Conn[0] > -1))
3572  {
3573  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl90set);
3574  }
3575  else if((Next.SpeedTag == 90) && (Next.Conn[0] == -1))
3576  {
3577  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl90unset);
3578  }
3579  if((Next.SpeedTag == 91) && (Next.Conn[0] > -1))
3580  {
3581  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl91set);
3582  }
3583  else if((Next.SpeedTag == 91) && (Next.Conn[0] == -1))
3584  {
3585  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl91unset);
3586  }
3587  if((Next.SpeedTag == 92) && (Next.Conn[0] > -1))
3588  {
3589  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl92set);
3590  }
3591  else if((Next.SpeedTag == 92) && (Next.Conn[0] == -1))
3592  {
3593  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl92unset);
3594  }
3595  if((Next.SpeedTag == 93) && (Next.Conn[0] > -1))
3596  {
3597  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm93set);
3598  }
3599  else if((Next.SpeedTag == 93) && (Next.Conn[0] == -1))
3600  {
3601  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm93unset);
3602  }
3603  if((Next.SpeedTag == 94) && (Next.Conn[0] > -1))
3604  {
3605  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm94set);
3606  }
3607  else if((Next.SpeedTag == 94) && (Next.Conn[0] == -1))
3608  {
3609  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm94unset);
3610  }
3611  if((Next.SpeedTag == 95) && (Next.Conn[0] > -1))
3612  {
3613  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl95set);
3614  }
3615  else if((Next.SpeedTag == 95) && (Next.Conn[0] == -1))
3616  {
3617  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl95unset);
3618  }
3619  }
3620  // below added for version 0.6, only stop signals to be drawn
3621  else if(Next.TrackType == SignalPost)
3622  {
3623  for(int x = 0; x < 40; x++)
3624  {
3625  if((SigTable[x].SpeedTag == Next.SpeedTag) && (SigTable[x].Attribute == 0)) // need to plot as red regardless of actual attribute value
3626  {
3627  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
3628  // note these blanks plotted on lh signal side, even for rh signals, but works ok because the platform is replotted
3629  // in PlatformOnSignalSide, which return true for platform NOT on signal side for rh sigs
3630  int HOffset = 0;
3631  if(Next.SpeedTag > 73)
3632  HOffset = 5;
3633  else if(Next.SpeedTag == 71)
3634  HOffset = 9;
3635  int VOffset = 0;
3636  if(Next.SpeedTag == 69)
3637  VOffset = 9;
3638  else if(Next.SpeedTag == 72)
3639  VOffset = 5;
3640  else if(Next.SpeedTag == 74)
3641  VOffset = 5;
3642  Graphics::TBitmap *GraphicPtr;
3643  if(Next.SpeedTag > 71)
3644  GraphicPtr = RailGraphics->bmDiagonalSignalBlank;
3645  else if(Next.SpeedTag < 70)
3646  GraphicPtr = RailGraphics->bmStraightNSSignalBlank;
3647  else
3648  GraphicPtr = RailGraphics->bmStraightEWSignalBlank;
3649  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16) + HOffset, ((Next.VLoc - GetVLocMin()) * 16) + VOffset, GraphicPtr);
3650  // plot special signal platform if present
3651  Graphics::TBitmap* SignalPlatformGraphic;
3652  if(PlatformOnSignalSide(2, Next.HLoc, Next.VLoc, Next.SpeedTag, SignalPlatformGraphic)) //
3653  {
3654  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SignalPlatformGraphic);
3655  }
3656  // now plot signal (double yellow overwrites most of signal platform if present)
3657  // below amended for version 0.6
3659  {
3660  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableThreeAspect[x].SigPtr);
3661  }
3662  else if(Next.SigAspect == TTrackElement::TwoAspect)
3663  {
3664  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableTwoAspect[x].SigPtr);
3665  }
3666  else if(Next.SigAspect == TTrackElement::GroundSignal)
3667  {
3668  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableGroundSignal[x].SigPtr);
3669  }
3670  else // 4 aspect
3671  {
3672  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTable[x].SigPtr);
3673  }
3674  break;
3675  }
3676  }
3677  }
3678  else
3679  {
3680  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), Next.GraphicPtr);
3681  }
3682  }
3683  }
3684  if(OldTransparentColour != clB5G5R5)
3685  {
3686  Utilities->clTransparent = OldTransparentColour; // restore
3689  }
3690  Utilities->CallLogPop(1533);
3691 }
3692 
3693 // ---------------------------------------------------------------------------
3694 
3695 void TTrack::WriteGraphicsToImage(int Caller, Graphics::TBitmap *Bitmap)
3696 {
3697  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WriteGraphicsToImage");
3698  if(UserGraphicVector.empty())
3699  {
3700  Utilities->CallLogPop(2192);
3701  return;
3702  }
3703  else
3704  {
3705  for(unsigned int x = 0; x < UserGraphicVector.size(); x++)
3706  {
3707  Bitmap->Canvas->CopyMode = cmSrcCopy;
3708  Bitmap->Canvas->Draw(UserGraphicVectorAt(26, x).HPos - (GetHLocMin() * 16), UserGraphicVectorAt(27, x).VPos - (GetVLocMin() * 16),
3709  UserGraphicVectorAt(28, x).UserGraphic->Graphic);
3710  }
3711  }
3712  Utilities->CallLogPop(2193);
3713 }
3714 
3715 // ---------------------------------------------------------------------------
3716 
3717 void TTrack::WriteOperatingTrackToImage(int Caller, Graphics::TBitmap *Bitmap)
3718 /*
3719  Note, have to plot inactives before track because track has to overwrite 'name' platforms (NamedLocationElements)
3720  Here plot all named elements as non-striped, points with active fillet, signals as they are set, and gaps as connected
3721 */
3722 {
3723  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WriteOperatingTrackToImage");
3724 // need to change graphics back to black on white if have a dark background
3725  TColor OldTransparentColour = Utilities->clTransparent;
3726 
3728  {
3729  Utilities->clTransparent = TColor(0xFFFFFF); // white
3732  }
3733  TTrackElement Next;
3734 
3735  Bitmap->Canvas->CopyMode = cmSrcCopy;
3737  Graphics::TBitmap *GraphicOutput;
3738 
3739  while(ReturnNextInactiveTrackElement(3, Next))
3740  {
3741  GraphicOutput = Next.GraphicPtr; // no striped name graphics
3742  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3743  {
3744  if(Next.SpeedTag == 144) // level crossing
3745  {
3746  int BaseElement = GetTrackElementFromTrackMap(3, Next.HLoc, Next.VLoc).SpeedTag;
3747  if(BaseElement == 1) // hor element
3748  {
3749  if(Next.Attribute == 1) // open to trains
3750  {
3751  GraphicOutput = RailGraphics->LCBothHor;
3752  }
3753  else // plot as closed to trains if in any other state
3754  {
3755  GraphicOutput = RailGraphics->LCBothVer;
3756  }
3757  }
3758  else // vert element
3759  {
3760  if(Next.Attribute == 1) // open to trains
3761  {
3762  GraphicOutput = RailGraphics->LCBothVer;
3763  }
3764  else // plot as closed to trains if in any other state
3765  {
3766  GraphicOutput = RailGraphics->LCBothHor;
3767  }
3768  }
3769  }
3770  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), GraphicOutput);
3771  }
3772  }
3773 
3774  NextTrackElementPtr = TrackVector.begin();
3775  while(ReturnNextTrackElement(3, Next))
3776  {
3777  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3778  {
3779  if(Next.TrackType == Points) // plot active fillet
3780  {
3781  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), Next.GraphicPtr);
3782  if(Next.SpeedTag < 28)
3783  {
3784  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3786  }
3787  else if(Next.SpeedTag < 132)
3788  {
3789  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3791  }
3792  else
3793  {
3794  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3796  }
3797  }
3798  else if(Next.TrackType == GapJump) // plot as connected
3799  {
3800  if(Next.SpeedTag == 88)
3801  {
3802  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl88set);
3803  }
3804  else if(Next.SpeedTag == 89)
3805  {
3806  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl89set);
3807  }
3808  else if(Next.SpeedTag == 90)
3809  {
3810  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl90set);
3811  }
3812  else if(Next.SpeedTag == 91)
3813  {
3814  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl91set);
3815  }
3816  else if(Next.SpeedTag == 92)
3817  {
3818  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl92set);
3819  }
3820  else if(Next.SpeedTag == 93)
3821  {
3822  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm93set);
3823  }
3824  else if(Next.SpeedTag == 94)
3825  {
3826  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm94set);
3827  }
3828  else if(Next.SpeedTag == 95)
3829  {
3830  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl95set);
3831  }
3832  }
3833  else if(Next.TrackType == SignalPost) // plot in correct colour
3834  {
3835  for(int x = 0; x < 40; x++)
3836  {
3837  if((SigTable[x].SpeedTag == Next.SpeedTag) && (SigTable[x].Attribute == Next.Attribute))
3838  {
3839  // plot blank first, then plot platform if present - (always not striped for operating railway)
3840  // note these blanks plotted on lh signal side, even for rh signals, but works ok because the platform is replotted
3841  // in PlatformOnSignalSide, which return true for platform NOT on signal side for rh sigs
3842  int HOffset = 0;
3843  if(Next.SpeedTag > 73)
3844  HOffset = 5;
3845  else if(Next.SpeedTag == 71)
3846  HOffset = 9;
3847  int VOffset = 0;
3848  if(Next.SpeedTag == 69)
3849  VOffset = 9;
3850  else if(Next.SpeedTag == 72)
3851  VOffset = 5;
3852  else if(Next.SpeedTag == 74)
3853  VOffset = 5;
3854  Graphics::TBitmap *GraphicPtr;
3855  if(Next.SpeedTag > 71)
3856  GraphicPtr = RailGraphics->bmDiagonalSignalBlank;
3857  else if(Next.SpeedTag < 70)
3858  GraphicPtr = RailGraphics->bmStraightNSSignalBlank;
3859  else
3860  GraphicPtr = RailGraphics->bmStraightEWSignalBlank;
3861  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16) + HOffset, ((Next.VLoc - GetVLocMin()) * 16) + VOffset, GraphicPtr);
3862  // plot special signal platform if present
3863  Graphics::TBitmap* SignalPlatformGraphic;
3864  if(PlatformOnSignalSide(1, Next.HLoc, Next.VLoc, Next.SpeedTag, SignalPlatformGraphic))
3865  {
3866  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SignalPlatformGraphic);
3867  }
3868  // now plot signal (double yellow overwrites most of signal platform if present)
3869  // below amended for version 0.6
3871  {
3872  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableThreeAspect[x].SigPtr);
3873  }
3874  else if(Next.SigAspect == TTrackElement::TwoAspect)
3875  {
3876  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableTwoAspect[x].SigPtr);
3877  }
3878  else if(Next.SigAspect == TTrackElement::GroundSignal)
3879  {
3880  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableGroundSignal[x].SigPtr);
3881  }
3882  else // 4 aspect
3883  {
3884  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTable[x].SigPtr);
3885  }
3886  if((Next.CallingOnSet) && (Next.SigAspect != TTrackElement::GroundSignal))
3887  // normal signal calling on, need to add extra graphic, basic red signal plotted above from SigTable
3888  {
3889  if(Next.SpeedTag == 68)
3890  {
3891  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm68CallingOn);
3892  }
3893  if(Next.SpeedTag == 69)
3894  {
3895  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm69CallingOn);
3896  }
3897  if(Next.SpeedTag == 70)
3898  {
3899  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm70CallingOn);
3900  }
3901  if(Next.SpeedTag == 71)
3902  {
3903  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm71CallingOn);
3904  }
3905  if(Next.SpeedTag == 72)
3906  {
3907  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm72CallingOn);
3908  }
3909  if(Next.SpeedTag == 73)
3910  {
3911  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm73CallingOn);
3912  }
3913  if(Next.SpeedTag == 74)
3914  {
3915  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm74CallingOn);
3916  }
3917  if(Next.SpeedTag == 75)
3918  {
3919  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm75CallingOn);
3920  }
3921  }
3922  else if((Next.CallingOnSet) && (Next.SigAspect == TTrackElement::GroundSignal)) // ground signal calling on, use normal proceed aspect
3923  {
3924  for(int x = 0; x < 40; x++)
3925  {
3926  if((SigTableGroundSignal[x].SpeedTag == Next.SpeedTag) && (SigTable[x].Attribute == 1)) // use attr 1 for proceed
3927  {
3928  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
3929  Display->PlotSignalBlankOnBitmap(Next.HLoc - GetHLocMin(), Next.VLoc - GetVLocMin(), Next.SpeedTag, Bitmap,
3930  Utilities->RHSignalFlag); // in case existing signal is a double yellow
3931  // plot special signal platform if present
3932  Graphics::TBitmap* SignalPlatformGraphic;
3933  if(PlatformOnSignalSide(4, Next.HLoc, Next.VLoc, Next.SpeedTag, SignalPlatformGraphic))
3934  {
3935  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SignalPlatformGraphic);
3936  }
3937  // now plot signal
3938  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableGroundSignal[x].SigPtr);
3939  break;
3940  }
3941  }
3942  }
3943  break;
3944  }
3945  }
3946  }
3947  else
3948  {
3949  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), Next.GraphicPtr);
3950  }
3951  }
3952  }
3953  if(OldTransparentColour != clB5G5R5)
3954  {
3955  Utilities->clTransparent = OldTransparentColour; // restore
3958  }
3959  Utilities->CallLogPop(1701);
3960 }
3961 
3962 // ---------------------------------------------------------------------------
3963 
3964 bool TTrack::FindAndHighlightAnUnsetGap(int Caller) // true if find one
3965 {
3966  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindAndHighlightAnUnsetGap");
3967  for(unsigned int x = 0; x < TrackVector.size(); x++)
3968  {
3969  if(TrackVector.at(x).TrackType == GapJump)
3970  {
3971  if(TrackVector.at(x).Conn[0] > -1)
3972  continue; // to next 'x' value as this element has already been set
3973  // here if identify a GapJump element not yet set
3974  GapPos = x;
3975  GapHLoc = TrackVector.at(x).HLoc;
3976  GapVLoc = TrackVector.at(x).VLoc;
3977  // highlight it
3979  Utilities->CallLogPop(469);
3980  return true;
3981  }
3982  }
3983  Utilities->CallLogPop(470);
3984  return false;
3985 }
3986 
3987 // ---------------------------------------------------------------------------
3988 
3989 bool TTrack::FindSetAndDisplayMatchingGap(int Caller, int HLoc, int VLoc) // true if find one
3990 {
3991  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindSetAndDisplayMatchingGap," + AnsiString(HLoc) + "," +
3992  AnsiString(VLoc));
3993  int Position;
3994  TTrackElement TrackElement;
3995 
3996  if(!(FindNonPlatformMatch(11, HLoc, VLoc, Position, TrackElement)))
3997  {
3998  Utilities->CallLogPop(471);
3999  return false; // not found
4000  }
4001  if(TrackElement.TrackType != GapJump)
4002  {
4003  Utilities->CallLogPop(472);
4004  return false; // found something but not a gap
4005  }
4006  if(Position == GapPos)
4007  {
4008  Utilities->CallLogPop(473);
4009  return false; // selected original gap
4010  }
4011  if(TrackVector.at(Position).Conn[0] != -1)
4012  {
4013  Utilities->CallLogPop(474);
4014  return false; // already selected
4015  }
4016  TrackVector.at(Position).Conn[0] = GapPos; // set Conn[0] at Position to GapPos & ConnLinkPos[0] to 0
4017  TrackVector.at(Position).ConnLinkPos[0] = 0;
4018  TrackVector.at(GapPos).Conn[0] = Position; // set other one similarly
4019  TrackVector.at(GapPos).ConnLinkPos[0] = 0;
4020 // now highlight the selected location
4021  Display->Ellipse(0, HLoc * 16, VLoc * 16, clB0G5R0);
4022  Utilities->CallLogPop(475);
4023  return true;
4024 }
4025 
4026 // ---------------------------------------------------------------------------
4027 
4028 bool TTrack::GapsUnset(int Caller)
4029  // returns true if there are gaps and any are unset
4030 {
4031  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GapsUnset");
4032  if(TrackVector.size() == 0)
4033  {
4034  Utilities->CallLogPop(476);
4035  return false;
4036  }
4037  for(unsigned int x = 0; x < TrackVector.size(); x++)
4038  {
4039  if(TrackVector.at(x).TrackType == GapJump)
4040  {
4041  if(TrackVector.at(x).Conn[0] == -1) // unset if -1 (Gap always at position 0)
4042  {
4043  Utilities->CallLogPop(477);
4044  return true;
4045  }
4046  else // set, but may not have matching element, or that element may not be set
4047  {
4048  if(TrackVector.at(TrackVector.at(x).Conn[0]).TrackType != GapJump)
4049  // check that the element pointed to by the gap link is a GapJump
4050  {
4051  ShowMessage("Error - gap connected to a non-gap. Railway file is corrupt, further use may cause a system crash");
4052  Utilities->CallLogPop(1137);
4053  return false;
4054  }
4055 // here if gap connection is itself a GapJump
4056  if(TrackVector.at(TrackVector.at(x).Conn[0]).Conn[0] != (int)x)
4057  // check that the element pointed to by the gap link is a GapJump & that its gap link
4058  // points back to 'x'
4059  {
4060  Utilities->CallLogPop(478);
4061  return true;
4062  }
4063 // here if gap connection itself points back to 'x' so these two GapJumps match properly
4064  }
4065  } // if(TrackVector.at(x).TrackType == GapJump)
4066  } // for x...
4067  Utilities->CallLogPop(479);
4068  return false;
4069 }
4070 
4071 // ---------------------------------------------------------------------------
4072 
4073 bool TTrack::NoGaps(int Caller) // returns true if there are no gaps
4074 {
4075  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NoGaps");
4076  for(unsigned int x = 0; x < TrackVector.size(); x++)
4077  {
4078  if(TrackVector.at(x).TrackType == GapJump)
4079  {
4080  Utilities->CallLogPop(1105);
4081  return false;
4082  }
4083  }
4084  Utilities->CallLogPop(1106);
4085  return true;
4086 }
4087 
4088 // ---------------------------------------------------------------------------
4089 
4090 bool TTrack::NoNamedLocationElements(int Caller) // returns true if there are no NamedLocationElements (includes footcrossings)
4091 {
4092  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NoLocations");
4093  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
4094  {
4095  if(InactiveTrackVector.at(x).FixedNamedLocationElement)
4096  {
4097  Utilities->CallLogPop(1107);
4098  return false;
4099  }
4100  }
4101  for(unsigned int x = 0; x < TrackVector.size(); x++)
4102  {
4103  if(TrackVector.at(x).FixedNamedLocationElement)
4104  {
4105  Utilities->CallLogPop(1108);
4106  return false;
4107  }
4108  }
4109  Utilities->CallLogPop(1109);
4110  return true;
4111 }
4112 
4113 // ---------------------------------------------------------------------------
4114 
4116  // returns true if there are unnamed NamedLocationElements (includes footcrossings)
4117  // returns false otherwise or if there are no NamedLocationElements
4118 {
4119  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LocationsNotNamed");
4120  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
4121  {
4122  if(InactiveTrackVector.at(x).FixedNamedLocationElement)
4123  {
4124  if(InactiveTrackVector.at(x).LocationName == "")
4125  {
4126  Utilities->CallLogPop(1110);
4127  return true;
4128  }
4129  }
4130  }
4131  for(unsigned int x = 0; x < TrackVector.size(); x++)
4132  {
4133  if(TrackVector.at(x).FixedNamedLocationElement)
4134  {
4135  if(TrackVector.at(x).LocationName == "")
4136  {
4137  Utilities->CallLogPop(1111);
4138  return true;
4139  }
4140  }
4141  }
4142  Utilities->CallLogPop(1112);
4143  return false;
4144 }
4145 
4146 // ---------------------------------------------------------------------------
4147 
4148 void TTrack::ShowSelectedGap(int Caller, TDisplay *Disp)
4149 {
4150  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ShowSelectedGap,");
4151  Disp->Ellipse(1, GapHLoc * 16, GapVLoc * 16, clB0G0R5);
4152  Utilities->CallLogPop(480);
4153 }
4154 
4155 // ---------------------------------------------------------------------------
4156 
4158 {
4159  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetAnyNonMatchingGaps");
4160  if(TrackVector.size() == 0)
4161  {
4162  Utilities->CallLogPop(481);
4163  return;
4164  }
4165  for(unsigned int x = 0; x < TrackVector.size(); x++)
4166  {
4167  if(TrackVector.at(x).TrackType == GapJump)
4168  {
4169  if(TrackVector.at(x).Conn[0] > -1) // set
4170  {
4171  if(TrackVector.at(TrackVector.at(x).Conn[0]).TrackType != GapJump)
4172  // check that the element pointed to by the gap link is a GapJump & if not clear Conns & CLks
4173  {
4174  TrackVector.at(x).Conn[0] = -1;
4175  TrackVector.at(x).ConnLinkPos[0] = -1;
4176  continue; // to next 'x'
4177  }
4178 // here if gap connection is itself a GapJump
4179  if(TrackVector.at(TrackVector.at(x).Conn[0]).Conn[0] != (int)x)
4180  // check that the element pointed to by the gap link is a GapJump & that its gap link points back to 'x'
4181  // if not clear Conns & CLks
4182  {
4183  TrackVector.at(x).Conn[0] = -1;
4184  TrackVector.at(x).ConnLinkPos[0] = -1;
4185  continue; // to next 'x'
4186  }
4187 // here if gap connection itself points back to 'x' so these two GapJumps match properly
4188 // hence no more action needed on these Conns & CLks
4189  }
4190  } // else //gap jump
4191  } // for x...
4192 // throw Exception("Test Exception");//test
4193  Utilities->CallLogPop(482);
4194 }
4195 
4196 // ---------------------------------------------------------------------------
4197 
4198 void TTrack::ResetSignals(int Caller)
4199 {
4200  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetSignals");
4201  for(unsigned int x = 0; x < TrackVector.size(); x++)
4202  {
4203  if(TrackVector.at(x).TrackType == SignalPost)
4204  {
4205  TrackVector.at(x).Attribute = 0;
4206  }
4207  }
4208  Utilities->CallLogPop(483);
4209 }
4210 
4211 // ---------------------------------------------------------------------------
4212 
4213 void TTrack::ResetPoints(int Caller)
4214 {
4215  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetPoints");
4216  for(unsigned int x = 0; x < TrackVector.size(); x++)
4217  {
4218  if(TrackVector.at(x).TrackType == Points)
4219  {
4220  TrackVector.at(x).Attribute = 0;
4221  }
4222  }
4223  Utilities->CallLogPop(484);
4224 }
4225 
4226 // ---------------------------------------------------------------------------
4227 
4228 bool TTrack::RepositionAndMapTrack(int Caller) // doesn't involve InactiveTrack
4229 {
4230  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RepositionAndMapTrack");
4231  if(TrackVector.empty())
4232  {
4233  TrackMap.clear();
4234  Utilities->CallLogPop(485);
4235  return true;
4236  }
4237 
4238 // build new vector from map (map already in ascending order of locations & no erase elements in map)
4239  THVPair TrackMapKeyPair;
4240 
4241  NewVector.clear();
4242  TTrackMapIterator TrackMapPtr;
4243 
4244  if(!TrackMap.empty())
4245  {
4246  for(TrackMapPtr = TrackMap.begin(); TrackMapPtr != TrackMap.end(); TrackMapPtr++)
4247  {
4248  NewVector.push_back(TrackElementAt(6, TrackMapPtr->second));
4249  }
4250  }
4251  if(NewVector.size() != TrackMap.size())
4252  {
4253  throw Exception("Error - Map & Vector different sizes");
4254  }
4255  unsigned int NonZeroCount = 0;
4256 
4257  for(unsigned int x = 0; x < TrackVector.size(); x++)
4258  {
4259  if(TrackVector.at(x).TrackType != Erase)
4260  NonZeroCount++;
4261  }
4262  if(NewVector.size() != NonZeroCount)
4263  {
4264  throw Exception("Error - NewVector & NonZero TrackVector different sizes");
4265  }
4266 
4268  TrackMap.clear(); // ready to rebuild map after repositioning of TrackVector elements
4269  TTrackMapEntry TrackMapEntry;
4270 
4271  for(unsigned int x = 0; x < TrackVector.size(); x++)
4272  {
4273  TrackMapKeyPair.first = TrackVector.at(x).HLoc;
4274  TrackMapKeyPair.second = TrackVector.at(x).VLoc;
4275  TrackMapEntry.first = TrackMapKeyPair;
4276  TrackMapEntry.second = x;
4277  if(!(TrackMap.insert(TrackMapEntry).second))
4278  {
4279  throw Exception("Error - map insertion failure, TrackVector in error");
4280  }
4281  }
4282 // All track now relocated in TrackVector, reset all Conns & CLks
4283  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
4284  {
4285  for(unsigned int y = 0; y < 4; y++)
4286  {
4287  TrackVector.at(x).Conn[y] = -1;
4288  TrackVector.at(x).ConnLinkPos[y] = -1;
4289  }
4290  }
4291  RebuildLocationNameMultiMap(1); // to ensure all position entries correct after track vector changes
4292  CheckMapAndTrack(4); // test
4293  CheckMapAndInactiveTrack(4); // test
4294  CheckLocationNameMultiMap(8); // test
4295  if(!ResetGapsFromGapMap(1))
4296  {
4297  Utilities->CallLogPop(489);
4298  return false;
4299  }
4300  Utilities->CallLogPop(490);
4301  return true;
4302 }
4303 
4304 // ---------------------------------------------------------------------------
4305 
4306 void TTrack::BuildGapMapFromTrackVector(int Caller) // Map contains one entry for each pair of matched gaps
4307 {
4308  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",BuildGapMapFromTrackVector");
4309  GapMap.clear();
4310  THVPair GapMapKeyPair, GapMapValuePair;
4311  TGapMapEntry GapMapEntry;
4312 
4313  for(unsigned int x = 0; x < TrackVector.size(); x++)
4314  {
4315  if(TrackVector.at(x).TrackType == GapJump)
4316  {
4317  GapMapKeyPair.first = TrackVector.at(x).HLoc;
4318  GapMapKeyPair.second = TrackVector.at(x).VLoc;
4319  GapMapEntry.first = GapMapKeyPair;
4320  if(TrackVector.at(x).Conn[0] == -1)
4321  {
4322  throw Exception("Error - Gap connection == -1 Can't build GapMap");
4323  }
4324  GapMapValuePair.first = TrackElementAt(7, TrackVector.at(x).Conn[0]).HLoc;
4325  GapMapValuePair.second = TrackElementAt(8, TrackVector.at(x).Conn[0]).VLoc;
4326  GapMapEntry.second = GapMapValuePair;
4327  if(GapMap.find(GapMapValuePair) == GapMap.end()) // if ValuePair already included as a key then result won't be end()
4328  {
4329  GapMap.insert(GapMapEntry);
4330  }
4331  }
4332  }
4333  Utilities->CallLogPop(492);
4334 }
4335 
4336 // ---------------------------------------------------------------------------
4337 
4338 bool TTrack::LinkTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool FinalCall)
4339 {
4340  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LinkTrack," + AnsiString((short)FinalCall));
4341  LocError = false;
4342  bool CheckForLinks = false;
4343 
4344  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
4345  {
4346  if(TrackVector.at(x).TrackType == Erase) //Erase isn't used any more as a track type
4347  continue; // skip blank elements
4348 // check footcrossing linkages
4349  if(TrackVector.at(x).TrackType == FootCrossing)
4350  {
4351  if(!CheckFootCrossingLinks(1, TrackVector.at(x)))
4352  {
4353  ShowMessage(
4354  "Footbridge or underpass connection error. Each end must connect to a platform, concourse or other footbridge or underpass, and they can't connect to each other");
4355  HLoc = TrackVector.at(x).HLoc;
4356  VLoc = TrackVector.at(x).VLoc;
4357  LocError = true;
4358  Utilities->CallLogPop(493);
4359  return false;
4360  }
4361  }
4362  for(unsigned int y = 0; y < 4; y++) // check all links for each element
4363  {
4364  CheckForLinks = false;
4365  if(TrackVector.at(x).Link[y] <= 0)
4366  continue; // no link
4367  if((TrackVector.at(x).TrackType == Buffers) && (TrackVector.at(x).Config[y] == End))
4368  continue; // buffer
4369  if(TrackVector.at(x).Config[y] == Gap)
4370  continue; // gaps set later from GapMap
4371 
4372  // get required H & V for track element joining link 'y'
4373  int NewHLoc = TrackVector.at(x).HLoc + LinkHVArray[TrackVector.at(x).Link[y]][0];
4374  int NewVLoc = TrackVector.at(x).VLoc + LinkHVArray[TrackVector.at(x).Link[y]][1];
4375  // find track element if present
4376  bool ConnectionFoundFlag;
4377  int VecPos = GetVectorPositionFromTrackMap(14, NewHLoc, NewVLoc, ConnectionFoundFlag);
4378  if((TrackVector.at(x).TrackType == Continuation) && (y == 0) && ConnectionFoundFlag)
4379  {
4380  ShowMessage("Can't have a track element adjacent to a continuation exit");
4381  HLoc = TrackVector.at(x).HLoc;
4382  VLoc = TrackVector.at(x).VLoc;
4383  LocError = true;
4384  if(FinalCall)
4385  {
4386  throw Exception("Error in final track linkage - continuation adjacent to another element");
4387  }
4388  Utilities->CallLogPop(1539);
4389  return false;
4390  }
4391  if((TrackVector.at(x).TrackType == Continuation) && (TrackVector.at(x).Config[y] == End))
4392  continue;
4393  if(ConnectionFoundFlag)
4394  {
4395  TrackVector.at(x).Conn[y] = VecPos;
4396  // find connecting link in the newly found track element if there is one & make buffer & adjacent signals check
4397  bool LinkFoundFlag = false;
4398  if((TrackVector.at(x).Config[1 - y] == Signal) && IsLCAtHV(50, TrackVector.at(VecPos).HLoc, TrackVector.at(VecPos).VLoc))
4399  { // new in v2.4.0 - Krizar (Kristian Zarebski) found this error
4400  ShowMessage("Can't have an exit signal next to a level crossing");
4401  // otherwise when single route element removed in front of train the LC will start to close and the train will crash
4402  }
4403  else if(((TrackVector.at(x).TrackType == Points) || (TrackVector.at(x).TrackType == SignalPost) || (TrackVector.at(x).TrackType == Crossover))
4404  && (TrackVector.at(VecPos).TrackType == Buffers))
4405  {
4406  ShowMessage("Can't have points, crossover or signal next to buffers - need room for a train without fouling");
4407  // need room for a train (2 elements) without fouling points or signals
4408  }
4409  else if(((TrackVector.at(x).TrackType == Points) || (TrackVector.at(x).TrackType == SignalPost) || (TrackVector.at(x).TrackType == Crossover) ||
4410  (TrackVector.at(x).TrackType == Bridge)) && (TrackVector.at(VecPos).TrackType == Continuation))
4411  {
4412  ShowMessage("Can't have points, crossover, bridge or signal next to a continuation");
4413  // route setting won't allow an end of route selection adjacent to an existing route, which would happen
4414  // if continuation next to a signal; also none of these can be a named location, and a continuation can
4415  // be named but needs the adjacent element named too
4416  }
4417  else if((TrackVector.at(x).TrackType == SignalPost) && (TrackVector.at(VecPos).TrackType == SignalPost) &&
4418  (TrackVector.at(x).SpeedTag == TrackVector.at(VecPos).SpeedTag))
4419  {
4420  ShowMessage("Can't have two same-direction signals adjacent to each other");
4421  // can't join a route to an existing route where the second signal is in an existing route and the first signal is
4422  // selected - appears as trying to select a signal that is not the next in line from the starting signal
4423  }
4424  else if(IsLCAtHV(45, TrackVector.at(x).HLoc, TrackVector.at(x).VLoc) && IsLCAtHV(46, TrackVector.at(VecPos).HLoc, TrackVector.at(VecPos).VLoc))
4425  // true if a level crossing is present at both x and VecPos - can't have two adjacent level crossings on the same track
4426  {
4427  ShowMessage("Can't have two level crossings adjacent to each other on the same track");
4428  }
4429  else
4430  CheckForLinks = true;
4431  if(CheckForLinks)
4432  {
4433  for(unsigned int a = 0; a < 4; a++)
4434  {
4435  if((TrackVector.at(VecPos).Link[a] == (10 - TrackVector.at(x).Link[y])) && (TrackVector.at(VecPos).Config[a] != End) &&
4436  (TrackVector.at(VecPos).Config[a] != Gap))
4437  {
4438  TrackVector.at(x).ConnLinkPos[y] = a;
4439  // note - this ensures that if the connecting element is a leading point
4440  // then the ConnLinkPos value is 0 rather than 2, since 'a' starts at 0
4441  // (Points have the same link value for both [0] and [2])
4442  LinkFoundFlag = true;
4443  break; // stop after first find or will find later link for leading point
4444  }
4445  }
4446  }
4447  // if there isn't a corresponding link, or buffer check fails, set the invert values for the offending element
4448  if(!LinkFoundFlag)
4449  {
4450  HLoc = TrackVector.at(x).HLoc;
4451  VLoc = TrackVector.at(x).VLoc;
4452  LocError = true;
4453  if(FinalCall)
4454  {
4455  throw Exception("Error in final track linkage - invalid link");
4456  }
4457  Utilities->CallLogPop(494);
4458  return false;
4459  }
4460  }
4461  // if there isn't a connection set the invert values for the offending element
4462  else // if(ConnectionFoundFlag)
4463  {
4464  HLoc = TrackVector.at(x).HLoc;
4465  VLoc = TrackVector.at(x).VLoc;
4466  LocError = true;
4467  if(FinalCall)
4468  {
4469  throw Exception("Error in final track linkage - connection not found");
4470  }
4471  Utilities->CallLogPop(495);
4472  return false;
4473  }
4474  }
4475  } // for(unsigned int x=0;x<TrackVector.size();x++)
4476 
4477  if(FinalCall)
4479 
4480 // final check
4481  bool ConnErrorFlag = false;
4482 
4483  for(unsigned int x = 0; x < TrackVector.size(); x++)
4484  {
4485  if((TrackVector.at(x).Link[0] > 0) && (TrackVector.at(x).Config[0] != End) && (TrackVector.at(x).Conn[0] == -1))
4486  ConnErrorFlag = true;
4487  if((TrackVector.at(x).Link[1] > 0) && (TrackVector.at(x).Config[1] != End) && (TrackVector.at(x).Conn[1] == -1))
4488  ConnErrorFlag = true;
4489  if((TrackVector.at(x).Link[2] > 0) && (TrackVector.at(x).Config[2] != End) && (TrackVector.at(x).Conn[2] == -1))
4490  ConnErrorFlag = true;
4491  if((TrackVector.at(x).Link[3] > 0) && (TrackVector.at(x).Config[3] != End) && (TrackVector.at(x).Conn[3] == -1))
4492  ConnErrorFlag = true;
4493  if(FinalCall) // StationStopLinks only set during FinalCall so only check at FinalCall
4494  {
4495  if(TrackVector.at(x).ActiveTrackElementName == "")
4496  {
4497  if((TrackVector.at(x).StationEntryStopLinkPos1 != -1) || (TrackVector.at(x).StationEntryStopLinkPos2 != -1))
4498  {
4499  throw Exception("Error, StationEntryStopLinkPos not -1 for unnamed element at TrackVectorPosition = " + AnsiString(x));
4500  }
4501  }
4502  }
4503  }
4504  if(ConnErrorFlag)
4505  {
4506  if(FinalCall)
4507  {
4508  throw Exception("ConnError in LinkTrack - Final");
4509  }
4510  else
4511  {
4512  throw Exception("ConnError in LinkTrack - Precheck");
4513  }
4514  }
4515 
4516  bool CLkErrorFlag = false;
4517 
4518  for(unsigned int x = 0; x < TrackVector.size(); x++)
4519  {
4520  if((TrackVector.at(x).Link[0] > 0) && (TrackVector.at(x).Config[0] != End) && (TrackVector.at(x).ConnLinkPos[0] == -1))
4521  CLkErrorFlag = true;
4522  if((TrackVector.at(x).Link[1] > 0) && (TrackVector.at(x).Config[1] != End) && (TrackVector.at(x).ConnLinkPos[1] == -1))
4523  CLkErrorFlag = true;
4524  if((TrackVector.at(x).Link[2] > 0) && (TrackVector.at(x).Config[2] != End) && (TrackVector.at(x).ConnLinkPos[2] == -1))
4525  CLkErrorFlag = true;
4526  if((TrackVector.at(x).Link[3] > 0) && (TrackVector.at(x).Config[3] != End) && (TrackVector.at(x).ConnLinkPos[3] == -1))
4527  CLkErrorFlag = true;
4528  }
4529 
4530  if(CLkErrorFlag)
4531  {
4532  if(FinalCall)
4533  {
4534  throw Exception("CLkError in LinkTrack - Final");
4535  }
4536  else
4537  {
4538  throw Exception("CLkError in LinkTrack - Precheck");
4539  }
4540  }
4541 
4542 // set element lengths to min of 20m
4543  for(unsigned int x = 0; x < TrackVector.size(); x++)
4544  {
4545  if(TrackVector.at(x).TrackType == Erase)
4546  continue; // skip blank elements
4547  if(TrackVector.at(x).Length01 < 20)
4548  TrackVector.at(x).Length01 = 20;
4549  if((TrackVector.at(x).Length23 < 20) && (TrackVector.at(x).Length23 != -1))
4550  TrackVector.at(x).Length23 = 20;
4551  }
4552 
4553  if(FinalCall) // ONLY at FinalCall, no point calling twice
4554  {
4555  CalcHLocMinEtc(3);
4556  }
4557  Utilities->CallLogPop(497);
4558  return true;
4559 }
4560 
4561 // ---------------------------------------------------------------------------
4562 
4563 bool TTrack::LinkTrackNoMessages(int Caller, bool FinalCall)
4564 {
4565  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LinkTrackNoMessages," + AnsiString((short)FinalCall));
4566  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
4567  {
4568  if(TrackVector.at(x).TrackType == Erase)
4569  continue; // skip blank elements
4570 
4571 // check footcrossing linkages
4572  if(TrackVector.at(x).TrackType == FootCrossing)
4573  {
4574  if(!CheckFootCrossingLinks(3, TrackVector.at(x)))
4575  {
4576  Utilities->CallLogPop(1127);
4577  return false;
4578  }
4579  }
4580 
4581  for(unsigned int y = 0; y < 4; y++) // check all links for each element
4582  {
4583  if(TrackVector.at(x).Link[y] <= 0)
4584  continue; // no link
4585  if((TrackVector.at(x).TrackType == Buffers) && (TrackVector.at(x).Config[y] == End))
4586  continue; // buffer
4587  if(TrackVector.at(x).Config[y] == Gap)
4588  continue; // gaps set later from GapMap
4589 
4590  // get required H & V for track element joining link 'y'
4591  int NewHLoc = TrackVector.at(x).HLoc + LinkHVArray[TrackVector.at(x).Link[y]][0];
4592  int NewVLoc = TrackVector.at(x).VLoc + LinkHVArray[TrackVector.at(x).Link[y]][1];
4593  // find track element if present
4594  bool ConnectionFoundFlag;
4595  int VecPos = GetVectorPositionFromTrackMap(38, NewHLoc, NewVLoc, ConnectionFoundFlag);
4596  if((TrackVector.at(x).TrackType == Continuation) && (y == 0) && ConnectionFoundFlag)
4597  {
4598  if(FinalCall)
4599  {
4600  throw Exception("Error in final track linkage - continuation adjacent to another element");
4601  }
4602  Utilities->CallLogPop(1540);
4603  return false;
4604  }
4605  if((TrackVector.at(x).TrackType == Continuation) && (TrackVector.at(x).Config[y] == End))
4606  continue;
4607  if(ConnectionFoundFlag)
4608  {
4609  TrackVector.at(x).Conn[y] = VecPos;
4610  bool LinkFoundFlag = false;
4611  // find connecting link in the newly found track element if there is one & make checks
4612  if(((TrackVector.at(x).TrackType == Points) || (TrackVector.at(x).TrackType == SignalPost) || (TrackVector.at(x).TrackType == Crossover)) &&
4613  (TrackVector.at(VecPos).TrackType == Buffers))
4614  {
4615  Utilities->CallLogPop(1541);
4616  return false;
4617  }
4618  else if(((TrackVector.at(x).TrackType == Points) || (TrackVector.at(x).TrackType == SignalPost) || (TrackVector.at(x).TrackType == Crossover) ||
4619  (TrackVector.at(x).TrackType == Bridge)) && (TrackVector.at(VecPos).TrackType == Continuation))
4620  {
4621  Utilities->CallLogPop(1542);
4622  return false;
4623  }
4624  else if((TrackVector.at(x).TrackType == SignalPost) && (TrackVector.at(VecPos).TrackType == SignalPost) &&
4625  (TrackVector.at(x).SpeedTag == TrackVector.at(VecPos).SpeedTag))
4626  {
4627  Utilities->CallLogPop(1543);
4628  return false;
4629  }
4630  else if(IsLCAtHV(47, TrackVector.at(x).HLoc, TrackVector.at(x).VLoc) && IsLCAtHV(48, TrackVector.at(VecPos).HLoc, TrackVector.at(VecPos).VLoc))
4631  // true if a level crossing is present at both x and VecPos - can't have two adjacent level crossings on the same track
4632  {
4633  Utilities->CallLogPop(1981);
4634  return false;
4635  }
4636 /* remove this restriction now that not permitted to treat a named continuation as a location stop
4637  else if(TrackVector.at(x).TrackType == Continuation)
4638  {
4639  int H = TrackVector.at(x).HLoc;
4640  int V = TrackVector.at(x).VLoc;
4641  bool FoundFlag = false;
4642  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(18, H, V, FoundFlag);
4643  if(FoundFlag)
4644  {
4645  if(InactiveTrackElementAt(93, IMPair.first).TrackType == NamedNonStationLocation)
4646  {
4647  int NewH = TrackElementAt(727, (TrackVector.at(x).Conn[1])).HLoc;
4648  int NewV = TrackElementAt(728, (TrackVector.at(x).Conn[1])).VLoc;
4649  TIMPair NewIMPair = GetVectorPositionsFromInactiveTrackMap(19, NewH, NewV, FoundFlag);
4650  if(FoundFlag)
4651  {
4652  if(InactiveTrackElementAt(94, NewIMPair.first).TrackType != NamedNonStationLocation)
4653  {
4654  Utilities->CallLogPop(1544);
4655  return false;
4656  }
4657  }
4658  else
4659  {
4660  Utilities->CallLogPop(1545);
4661  return false;
4662  }
4663  }
4664  }
4665  }
4666 */
4667  for(unsigned int a = 0; a < 4; a++)
4668  {
4669  if((TrackVector.at(VecPos).Link[a] == (10 - TrackVector.at(x).Link[y])) && (TrackVector.at(VecPos).Config[a] != End) &&
4670  (TrackVector.at(VecPos).Config[a] != Gap))
4671  {
4672  TrackVector.at(x).ConnLinkPos[y] = a;
4673  // note - this ensures that if the connecting element is a leading point
4674  // then the ConnLinkPos value is 0 rather than 2, since 'a' starts at 0
4675  // (Points have the same link value for both [0] and [2])
4676  LinkFoundFlag = true;
4677  break; // stop after first find or will find later link for leading point
4678  }
4679  }
4680  if(!LinkFoundFlag)
4681  {
4682  if(FinalCall)
4683  {
4684  throw Exception("Error in final track linkage in LinkTrackNoMessages - invalid link");
4685  }
4686  Utilities->CallLogPop(1128);
4687  return false;
4688  }
4689  }
4690  else // if(ConnectionFoundFlag)
4691  {
4692  if(FinalCall)
4693  {
4694  throw Exception("Error in final track linkage in LinkTrackNoMessages - connection not found");
4695  }
4696  Utilities->CallLogPop(1129);
4697  return false;
4698  }
4699  }
4700  } // for(unsigned int x=0;x<TrackVector.size();x++)
4701 
4702  if(FinalCall)
4704 
4705 // final check
4706  bool ConnErrorFlag = false;
4707 
4708  for(unsigned int x = 0; x < TrackVector.size(); x++)
4709  {
4710  if((TrackVector.at(x).Link[0] > 0) && (TrackVector.at(x).Config[0] != End) && (TrackVector.at(x).Conn[0] == -1))
4711  ConnErrorFlag = true;
4712  if((TrackVector.at(x).Link[1] > 0) && (TrackVector.at(x).Config[1] != End) && (TrackVector.at(x).Conn[1] == -1))
4713  ConnErrorFlag = true;
4714  if((TrackVector.at(x).Link[2] > 0) && (TrackVector.at(x).Config[2] != End) && (TrackVector.at(x).Conn[2] == -1))
4715  ConnErrorFlag = true;
4716  if((TrackVector.at(x).Link[3] > 0) && (TrackVector.at(x).Config[3] != End) && (TrackVector.at(x).Conn[3] == -1))
4717  ConnErrorFlag = true;
4718  if(FinalCall) // StationStopLinks only set during FinalCall so only check at FinalCall
4719  {
4720  if(TrackVector.at(x).ActiveTrackElementName == "")
4721  {
4722  if((TrackVector.at(x).StationEntryStopLinkPos1 != -1) || (TrackVector.at(x).StationEntryStopLinkPos2 != -1))
4723  {
4724  throw Exception("Error, StationEntryStopLinkPos not -1 for unnamed element at TrackVectorPosition = " + AnsiString(x));
4725  }
4726  }
4727  }
4728  }
4729  if(ConnErrorFlag)
4730  {
4731  if(FinalCall)
4732  {
4733  throw Exception("ConnError in LinkTrack - Final");
4734  }
4735  else
4736  {
4737  throw Exception("ConnError in LinkTrack - Precheck");
4738  }
4739  }
4740 
4741  bool CLkErrorFlag = false;
4742 
4743  for(unsigned int x = 0; x < TrackVector.size(); x++)
4744  {
4745  if((TrackVector.at(x).Link[0] > 0) && (TrackVector.at(x).Config[0] != End) && (TrackVector.at(x).ConnLinkPos[0] == -1))
4746  CLkErrorFlag = true;
4747  if((TrackVector.at(x).Link[1] > 0) && (TrackVector.at(x).Config[1] != End) && (TrackVector.at(x).ConnLinkPos[1] == -1))
4748  CLkErrorFlag = true;
4749  if((TrackVector.at(x).Link[2] > 0) && (TrackVector.at(x).Config[2] != End) && (TrackVector.at(x).ConnLinkPos[2] == -1))
4750  CLkErrorFlag = true;
4751  if((TrackVector.at(x).Link[3] > 0) && (TrackVector.at(x).Config[3] != End) && (TrackVector.at(x).ConnLinkPos[3] == -1))
4752  CLkErrorFlag = true;
4753  }
4754 
4755  if(CLkErrorFlag)
4756  {
4757  if(FinalCall)
4758  {
4759  throw Exception("CLkError in LinkTrack - Final");
4760  }
4761  else
4762  {
4763  throw Exception("CLkError in LinkTrack - Precheck");
4764  }
4765  }
4766 
4767 // set element lengths to min of 20m
4768  for(unsigned int x = 0; x < TrackVector.size(); x++)
4769  {
4770  if(TrackVector.at(x).TrackType == Erase)
4771  continue; // skip blank elements
4772  if(TrackVector.at(x).Length01 < 20)
4773  TrackVector.at(x).Length01 = 20;
4774  if((TrackVector.at(x).Length23 < 20) && (TrackVector.at(x).Length23 != -1))
4775  TrackVector.at(x).Length23 = 20;
4776  }
4777 
4778  if(FinalCall) // ONLY at FinalCall, no point calling twice
4779  {
4780  CalcHLocMinEtc(7);
4781  }
4782  Utilities->CallLogPop(1130);
4783  return true;
4784 }
4785 
4786 // ---------------------------------------------------------------------------
4787 
4788 bool TTrack::IsTrackLinked(int Caller) // not used any more
4789 {
4790  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsTrackLinked");
4791  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
4792  {
4793  if(TrackVector.at(x).TrackType == Erase)
4794  {
4795  Utilities->CallLogPop(498);
4796  return false;
4797  }
4798 
4799 // check foot linkages
4800  if(TrackVector.at(x).TrackType == FootCrossing)
4801  {
4802  if(!CheckFootCrossingLinks(2, TrackVector.at(x)))
4803  {
4804  Utilities->CallLogPop(499);
4805  return false;
4806  }
4807  }
4808 
4809  for(unsigned int y = 0; y < 4; y++) // check all links for each element
4810  {
4811  if(TrackVector.at(x).Link[y] <= 0)
4812  continue; // no link
4813  if(TrackVector.at(x).Config[y] == End)
4814  continue; // buffer or continuation
4815  if(TrackVector.at(x).Config[y] == Gap)
4816  continue; // gaps set later from GapMap
4817 
4818  // get required H & V for track element joining link 'y'
4819  int NewHLoc = TrackVector.at(x).HLoc + LinkHVArray[TrackVector.at(x).Link[y]][0];
4820  int NewVLoc = TrackVector.at(x).VLoc + LinkHVArray[TrackVector.at(x).Link[y]][1];
4821  // find track element if present
4822  bool ConnectionFoundFlag = false;
4823  int VecPos = GetVectorPositionFromTrackMap(15, NewHLoc, NewVLoc, ConnectionFoundFlag);
4824  if(ConnectionFoundFlag)
4825  {
4826  TrackVector.at(x).Conn[y] = VecPos;
4827  // find connecting link in the newly found track element if there is one & make buffer check
4828  bool LinkFoundFlag = false;
4829  if(((TrackVector.at(x).TrackType == Points) || (TrackVector.at(x).TrackType == SignalPost) || (TrackVector.at(x).TrackType == Crossover)) &&
4830  (TrackVector.at(VecPos).TrackType == Buffers))
4831  {
4832  Utilities->CallLogPop(500);
4833  return false;
4834  }
4835  else if((TrackVector.at(x).TrackType == SignalPost) && (TrackVector.at(VecPos).TrackType == SignalPost) &&
4836  (TrackVector.at(x).SpeedTag == TrackVector.at(VecPos).SpeedTag))
4837  {
4838  Utilities->CallLogPop(501);
4839  return false;
4840  }
4841  else if((TrackVector.at(x).TrackType == SignalPost) && (TrackVector.at(VecPos).TrackType == Continuation))
4842  {
4843  Utilities->CallLogPop(502);
4844  return false;
4845  }
4846  else
4847  {
4848  for(unsigned int a = 0; a < 4; a++)
4849  {
4850  if((TrackVector.at(VecPos).Link[a] == (10 - TrackVector.at(x).Link[y])) && (TrackVector.at(VecPos).Config[a] != End) &&
4851  (TrackVector.at(VecPos).Config[a] != Gap))
4852  {
4853  TrackVector.at(x).ConnLinkPos[y] = a;
4854  // note - this ensures that if the connecting element is a leading point
4855  // then the ConnLinkPos value is 0 rather than 2, since 'a' starts at 0
4856  // (Points have the same link value for both [0] and [2])
4857  LinkFoundFlag = true;
4858  break; // stop after first find or will find later link for leading point
4859  }
4860  }
4861  }
4862  if(!LinkFoundFlag)
4863  {
4864  Utilities->CallLogPop(503);
4865  return false;
4866  }
4867  }
4868  else // if(ConnectionFoundFlag)
4869  {
4870  Utilities->CallLogPop(504);
4871  return false;
4872  }
4873  }
4874  } // for(unsigned int x=0;x<TrackVector.size();x++)
4875 
4876 // final check
4877  bool ConnErrorFlag = false;
4878 
4879  for(unsigned int x = 0; x < TrackVector.size(); x++)
4880  {
4881  if((TrackVector.at(x).Link[0] > 0) && (TrackVector.at(x).Config[0] != End) && (TrackVector.at(x).Conn[0] == -1))
4882  ConnErrorFlag = true;
4883  if((TrackVector.at(x).Link[1] > 0) && (TrackVector.at(x).Config[1] != End) && (TrackVector.at(x).Conn[1] == -1))
4884  ConnErrorFlag = true;
4885  if((TrackVector.at(x).Link[2] > 0) && (TrackVector.at(x).Config[2] != End) && (TrackVector.at(x).Conn[2] == -1))
4886  ConnErrorFlag = true;
4887  if((TrackVector.at(x).Link[3] > 0) && (TrackVector.at(x).Config[3] != End) && (TrackVector.at(x).Conn[3] == -1))
4888  ConnErrorFlag = true;
4889  }
4890  if(ConnErrorFlag)
4891  {
4892  Utilities->CallLogPop(505);
4893  return false;
4894  }
4895 
4896  bool CLkErrorFlag = false;
4897 
4898  for(unsigned int x = 0; x < TrackVector.size(); x++)
4899  {
4900  if((TrackVector.at(x).Link[0] > 0) && (TrackVector.at(x).Config[0] != End) && (TrackVector.at(x).ConnLinkPos[0] == -1))
4901  CLkErrorFlag = true;
4902  if((TrackVector.at(x).Link[1] > 0) && (TrackVector.at(x).Config[1] != End) && (TrackVector.at(x).ConnLinkPos[1] == -1))
4903  CLkErrorFlag = true;
4904  if((TrackVector.at(x).Link[2] > 0) && (TrackVector.at(x).Config[2] != End) && (TrackVector.at(x).ConnLinkPos[2] == -1))
4905  CLkErrorFlag = true;
4906  if((TrackVector.at(x).Link[3] > 0) && (TrackVector.at(x).Config[3] != End) && (TrackVector.at(x).ConnLinkPos[3] == -1))
4907  CLkErrorFlag = true;
4908  }
4909 
4910  if(CLkErrorFlag)
4911  {
4912  Utilities->CallLogPop(506);
4913  return false;
4914  }
4915  Utilities->CallLogPop(507);
4916  return true;
4917 }
4918 
4919 // ---------------------------------------------------------------------------
4920 
4922 {
4923  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetGapsFromGapMap");
4924  int Position1, Position2;
4925  TTrackElement TrackElement1, TrackElement2;
4926  TGapMapIterator GapMapPtr;
4927 
4928  if(!GapMap.empty())
4929  {
4930  for(GapMapPtr = GapMap.begin(); GapMapPtr != GapMap.end(); GapMapPtr++)
4931  {
4932  int HLoc1 = GapMapPtr->first.first;
4933  int VLoc1 = GapMapPtr->first.second;
4934  int HLoc2 = GapMapPtr->second.first;
4935  int VLoc2 = GapMapPtr->second.second;
4936  if(!FindNonPlatformMatch(12, HLoc1, VLoc1, Position1, TrackElement1))
4937  {
4938  throw Exception("Failed to find H & V for gap1, GapMap in error");
4939  }
4940  if(!FindNonPlatformMatch(13, HLoc2, VLoc2, Position2, TrackElement2))
4941  {
4942  throw Exception("Failed to find H & V for gap2, GapMap in error");
4943  }
4944  if(TrackElementAt(9, Position1).TrackType != GapJump)
4945  {
4946  throw Exception("Element at Pos1 not a gap, GapMap in error");
4947  }
4948  if(TrackElementAt(10, Position2).TrackType != GapJump)
4949  {
4950  throw Exception("Element at Pos2 not a gap, GapMap in error");
4951  }
4952  TrackElementAt(11, Position1).Conn[0] = Position2;
4953  TrackElementAt(12, Position1).ConnLinkPos[0] = 0;
4954  TrackElementAt(13, Position2).Conn[0] = Position1;
4955  TrackElementAt(14, Position2).ConnLinkPos[0] = 0;
4956  }
4957  }
4958  Utilities->CallLogPop(510);
4959  return true;
4960 }
4961 
4962 // ---------------------------------------------------------------------------
4963 
4964 void TTrack::TrackPush(int Caller, TTrackElement TrackElement)
4965 {
4966 // TIMPair MapEntry;
4967  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackPush," + AnsiString(TrackElement.HLoc) + "," +
4968  AnsiString(TrackElement.VLoc) + "," + AnsiString(TrackElement.SpeedTag));
4969  THVPair TrackMapKeyPair, InactiveTrackMapKeyPair;
4970  TTrackMapEntry TrackMapEntry, InactiveTrackMapEntry;
4971  TLocationNameMultiMapEntry LocationNameEntry;
4972 
4973  LocationNameEntry.first = TrackElement.LocationName;
4974  if((TrackElement.TrackType == Platform) || (TrackElement.TrackType == Concourse) || (TrackElement.TrackType == Parapet) ||
4975  (TrackElement.TrackType == NamedNonStationLocation) || (TrackElement.TrackType == LevelCrossing))
4976  {
4977 // check whether a similar element already at this position and if so ignore it (had error where allowed multiple NonStationNamedLocs)
4978 // could arise when loading old railways with multiple NonStationNamedLocs
4979  bool FoundFlag = false;
4980  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(20, TrackElement.HLoc, TrackElement.VLoc, FoundFlag);
4981  if(FoundFlag)
4982  {
4983  if((InactiveTrackElementAt(97, IMPair.first).SpeedTag == TrackElement.SpeedTag) || (InactiveTrackElementAt(98,
4984  IMPair.second).SpeedTag == TrackElement.SpeedTag))
4985  {
4986  Utilities->CallLogPop(1813);
4987  return;
4988  }
4989  }
4990  InactiveTrackVector.push_back(TrackElement); // no erase elements involved in InactiveTrackVector
4991  InactiveTrackMapKeyPair.first = TrackElement.HLoc;
4992  InactiveTrackMapKeyPair.second = TrackElement.VLoc;
4993  InactiveTrackMapEntry.first = InactiveTrackMapKeyPair;
4994  InactiveTrackMapEntry.second = InactiveTrackVector.size() - 1;
4995  InactiveTrack2MultiMap.insert(InactiveTrackMapEntry);
4996  if(TrackElement.FixedNamedLocationElement)
4997  {
4998  LocationNameEntry.second = InactiveTrackVector.size() - 1; // add to LocationNameMultiMap
4999  LocationNameMultiMap.insert(LocationNameEntry);
5000  }
5001  if(TrackElement.HLoc < HLocMin)
5002  HLocMin = TrackElement.HLoc;
5003  if(TrackElement.HLoc > HLocMax)
5004  HLocMax = TrackElement.HLoc;
5005  if(TrackElement.VLoc < VLocMin)
5006  VLocMin = TrackElement.VLoc;
5007  if(TrackElement.VLoc > VLocMax)
5008  VLocMax = TrackElement.VLoc;
5009  }
5010  else
5011  {
5012 // check whether a similar element already at this position and if so ignore it (had error where allowed multiple NonStationNamedLocs)
5013 // shouldn't arise but leave in as a safeguard
5014  bool FoundFlag = false;
5015  int VecPos = GetVectorPositionFromTrackMap(44, TrackElement.HLoc, TrackElement.VLoc, FoundFlag);
5016  if(FoundFlag)
5017  {
5018  if(TrackElementAt(816, VecPos).SpeedTag == TrackElement.SpeedTag)
5019  {
5020  Utilities->CallLogPop(1814);
5021  return;
5022  }
5023  }
5024  TrackVector.push_back(TrackElement); // add erase elements to vector to keep linkages correct (now dispensed with)
5025  if(TrackElement.TrackType != Erase) // don't add erase elements to TrackMap (dispensed with these but keep code)
5026  {
5027  TrackMapKeyPair.first = TrackElement.HLoc;
5028  TrackMapKeyPair.second = TrackElement.VLoc;
5029  TrackMapEntry.first = TrackMapKeyPair;
5030  TrackMapEntry.second = TrackVector.size() - 1;
5031  TrackMap.insert(TrackMapEntry);
5032  if(TrackElement.FixedNamedLocationElement)
5033  {
5034  LocationNameEntry.second = -(int)(TrackVector.size()); // add to LocationNameMultiMap
5035  LocationNameMultiMap.insert(LocationNameEntry);
5036  }
5037  if(TrackElement.HLoc < HLocMin)
5038  HLocMin = TrackElement.HLoc; // exclude erase elements as HLoc & VLoc set to -2000000000
5039  if(TrackElement.HLoc > HLocMax)
5040  HLocMax = TrackElement.HLoc;
5041  if(TrackElement.VLoc < VLocMin)
5042  VLocMin = TrackElement.VLoc;
5043  if(TrackElement.VLoc > VLocMax)
5044  VLocMax = TrackElement.VLoc;
5045  }
5046  }
5047 // CheckMapAndTrack(6);//test drop these to speed up, still checked outside this function
5048 // CheckMapAndInactiveTrack(6);//test
5049 
5050 // CheckLocationNameMultiMap(14);//test Can't test here as when loading the ActiveTrackElementName elements will be out of step
5051 // with the Platforms until layout fully loaded
5052  Utilities->CallLogPop(511);
5053 }
5054 
5055 // ---------------------------------------------------------------------------
5056 
5057 int TTrack::GetVectorPositionFromTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
5058 {
5059  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetVectorPositionFromTrackMap," + AnsiString(HLoc) + "," +
5060  AnsiString(VLoc));
5061  THVPair TrackMapKeyPair;
5062 
5063  FoundFlag = false;
5064  TTrackMapIterator TrackMapPtr;
5065 
5066  TrackMapKeyPair.first = HLoc;
5067  TrackMapKeyPair.second = VLoc;
5068  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
5069  if(TrackMapPtr == TrackMap.end())
5070  {
5071  Utilities->CallLogPop(512);
5072  return -1; // nothing found
5073  }
5074  else
5075  {
5076  FoundFlag = true;
5077  Utilities->CallLogPop(513);
5078  return TrackMapPtr->second;
5079  }
5080 }
5081 
5082 // ---------------------------------------------------------------------------
5083 
5084 TTrackElement &TTrack::GetTrackElementFromTrackMap(int Caller, int HLoc, int VLoc)
5085 {
5086  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackElementFromTrackMap," + AnsiString(HLoc) + "," +
5087  AnsiString(VLoc));
5088  THVPair TrackMapKeyPair;
5089  TTrackMapIterator TrackMapPtr;
5090 
5091  TrackMapKeyPair.first = HLoc;
5092  TrackMapKeyPair.second = VLoc;
5093  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
5094  if(TrackMapPtr == TrackMap.end())
5095  {
5096  AnsiString Message = "Element not found at HLoc " + AnsiString(HLoc) + " and VLoc " + AnsiString(VLoc);
5097  throw Exception(Message);
5098  }
5099  else
5100  {
5101  Utilities->CallLogPop(1943);
5102  return TrackElementAt(871, TrackMapPtr->second);
5103  }
5104 }
5105 
5106 // ---------------------------------------------------------------------------
5107 
5109 {
5110  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetInactiveTrackElementFromTrackMap," + AnsiString(HLoc) + "," +
5111  AnsiString(VLoc));
5112  THVPair InactiveTrackMapKeyPair;
5113  TInactiveTrack2MultiMapIterator InactiveTrackMapPtr;
5114 
5115  InactiveTrackMapKeyPair.first = HLoc;
5116  InactiveTrackMapKeyPair.second = VLoc;
5117  InactiveTrackMapPtr = InactiveTrack2MultiMap.find(InactiveTrackMapKeyPair); // not interested in platforms so only need to find one
5118  if(InactiveTrackMapPtr == InactiveTrack2MultiMap.end())
5119  {
5120  AnsiString Message = "Inactive element not found at HLoc " + AnsiString(HLoc) + " and VLoc " + AnsiString(VLoc);
5121  throw Exception(Message);
5122  }
5123  else
5124  {
5125  Utilities->CallLogPop(1949);
5126  return InactiveTrackElementAt(34, InactiveTrackMapPtr->second);
5127  }
5128 }
5129 
5130 // ---------------------------------------------------------------------------
5131 
5132 bool TTrack::TrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
5133 {
5134  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackElementPresentAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
5135  bool Present = true;
5136  THVPair TrackMapKeyPair;
5137  TTrackMapIterator TrackMapPtr;
5138 
5139  TrackMapKeyPair.first = HLoc;
5140  TrackMapKeyPair.second = VLoc;
5141  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
5142  if(TrackMapPtr == TrackMap.end())
5143  {
5144  Present = false;
5145  }
5146  Utilities->CallLogPop(2057);
5147  return Present;
5148 }
5149 
5150 // ---------------------------------------------------------------------------
5151 
5152 bool TTrack::InactiveTrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
5153 {
5154  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",InactiveTrackElementPresentAtHV," + AnsiString(HLoc) + "," +
5155  AnsiString(VLoc));
5156  bool Present = true;
5157  THVPair InactiveTrackMapKeyPair;
5158  TInactiveTrack2MultiMapIterator InactiveTrackMapPtr;
5159 
5160  InactiveTrackMapKeyPair.first = HLoc;
5161  InactiveTrackMapKeyPair.second = VLoc;
5162  InactiveTrackMapPtr = InactiveTrack2MultiMap.find(InactiveTrackMapKeyPair); // not interested in platforms so only need to find one
5163  if(InactiveTrackMapPtr == InactiveTrack2MultiMap.end())
5164  {
5165  Present = false;
5166  }
5167  Utilities->CallLogPop(2058);
5168  return Present;
5169 }
5170 
5171 // ---------------------------------------------------------------------------
5172 
5173 TTrack::TIMPair TTrack::GetVectorPositionsFromInactiveTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
5174  // max number of elements is 2, for platforms
5175  // note that both elements of RetPair may be the same, if only one present in map
5176 {
5177  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetVectorPositionsFromInactiveTrackMap," + AnsiString(HLoc) + "," +
5178  AnsiString(VLoc));
5179  THVPair InactiveTrackMapKeyPair;
5180  TIMPair RetPair;
5181  TInactiveTrackRange InactiveTrackRange;
5182 
5183  FoundFlag = false;
5184  InactiveTrackMapKeyPair.first = HLoc;
5185  InactiveTrackMapKeyPair.second = VLoc;
5186  if(InactiveTrack2MultiMap.empty())
5187  {
5188  RetPair.first = 0;
5189  RetPair.second = 0;
5190  Utilities->CallLogPop(1815);
5191  return RetPair; // map empty
5192  }
5193  InactiveTrackRange = InactiveTrack2MultiMap.equal_range(InactiveTrackMapKeyPair);
5194  if(InactiveTrackRange.first == InactiveTrackRange.second)
5195  {
5196  RetPair.first = 0;
5197  RetPair.second = 0;
5198  Utilities->CallLogPop(514);
5199  return RetPair; // nothing found
5200  }
5201  else
5202  {
5203  RetPair.first = InactiveTrackRange.first->second;
5204  RetPair.second = (--InactiveTrackRange.second)->second;
5205  FoundFlag = true;
5206  Utilities->CallLogPop(515);
5207  return RetPair;
5208  }
5209 }
5210 
5211 // ---------------------------------------------------------------------------
5212 
5213 bool TTrack::MatchingPoint(int Caller, unsigned int TrackVectorPosition, unsigned int DivergingPosition)
5214 {
5215 // only change where have adjacent points with their diverging links connected - not appropriate for non-straight points
5216  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",MatchingPoint," + AnsiString(TrackVectorPosition) + "," +
5217  AnsiString(DivergingPosition));
5218  TTrackElement T1 = TrackElementAt(15, TrackVectorPosition);
5219  TTrackElement T2 = TrackElementAt(16, DivergingPosition);
5220  int SpeedTag1 = T1.SpeedTag;
5221  int SpeedTag2 = T2.SpeedTag;
5222 
5223  if(T1.Attribute != T2.Attribute)
5224  {
5225  Utilities->CallLogPop(516);
5226  return false;
5227  }
5228  if(((SpeedTag1 == 7) && (SpeedTag2 == 10)) || // straight track hor, diverging track vert
5229  ((SpeedTag1 == 10) && (SpeedTag2 == 7)) || ((SpeedTag1 == 8) && (SpeedTag2 == 9)) || ((SpeedTag1 == 9) && (SpeedTag2 == 8)) ||
5230  ((SpeedTag1 == 11) && (SpeedTag2 == 14)) || // straight track vert, diverging track hor
5231  ((SpeedTag1 == 14) && (SpeedTag2 == 11)) || ((SpeedTag1 == 12) && (SpeedTag2 == 13)) || ((SpeedTag1 == 13) && (SpeedTag2 == 12)) ||
5232  ((SpeedTag1 == 28) && (SpeedTag2 == 31)) || // straight track hor, diverging track 45 deg
5233  ((SpeedTag1 == 31) && (SpeedTag2 == 28)) || ((SpeedTag1 == 29) && (SpeedTag2 == 30)) || ((SpeedTag1 == 30) && (SpeedTag2 == 29)) ||
5234  ((SpeedTag1 == 32) && (SpeedTag2 == 35)) || // straight track vert, diverging track 45 deg
5235  ((SpeedTag1 == 35) && (SpeedTag2 == 32)) || ((SpeedTag1 == 33) && (SpeedTag2 == 34)) || ((SpeedTag1 == 34) && (SpeedTag2 == 33)) ||
5236  ((SpeedTag1 == 36) && (SpeedTag2 == 39)) || // straight track 45 deg, diverging track vert
5237  ((SpeedTag1 == 39) && (SpeedTag2 == 36)) || ((SpeedTag1 == 37) && (SpeedTag2 == 38)) || ((SpeedTag1 == 38) && (SpeedTag2 == 37)) ||
5238  ((SpeedTag1 == 40) && (SpeedTag2 == 43)) || // straight track 45 deg, diverging track hor
5239  ((SpeedTag1 == 43) && (SpeedTag2 == 40)) || ((SpeedTag1 == 41) && (SpeedTag2 == 42)) || ((SpeedTag1 == 42) && (SpeedTag2 == 41)))
5240  {
5241  Utilities->CallLogPop(517);
5242  return true;
5243  }
5244  else
5245  {
5246  Utilities->CallLogPop(518);
5247  return false;
5248  }
5249 }
5250 
5251 // ---------------------------------------------------------------------------
5252 
5253 /*
5254  bool TMapComp::operator() (const THVPair& lower, const THVPair& higher) const///HLoc VLoc
5255  {
5256  if(lower.second < higher.second) return true;
5257  else if(lower.second > higher.second) return false;
5258  else if(lower.second == higher.second)
5259  {
5260  if(lower.first < higher.first) return true;
5261  }
5262  return false;
5263  }
5264 */
5265 // ---------------------------------------------------------------------------
5266 
5267 void TTrack::PlotGap(int Caller, TTrackElement TrackElement, TDisplay *Disp)
5268  // no need to check corresponding gap, if that not set correctly it will be picked up in GapsUnset()
5269 {
5270  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotGap," + TrackElement.LogTrack(1));
5271  if(TrackElement.TrackType != GapJump)
5272  {
5273  throw Exception("Error, Wrong track type in PlotGap");
5274  }
5275  if((TrackElement.SpeedTag == 88) && (TrackElement.Conn[0] > -1))
5276  {
5277  Disp->PlotOutput(39, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl88set);
5278  }
5279  else if((TrackElement.SpeedTag == 88) && (TrackElement.Conn[0] == -1))
5280  {
5281  Disp->PlotOutput(40, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl88unset);
5282  }
5283  if((TrackElement.SpeedTag == 89) && (TrackElement.Conn[0] > -1))
5284  {
5285  Disp->PlotOutput(41, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl89set);
5286  }
5287  else if((TrackElement.SpeedTag == 89) && (TrackElement.Conn[0] == -1))
5288  {
5289  Disp->PlotOutput(42, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl89unset);
5290  }
5291  if((TrackElement.SpeedTag == 90) && (TrackElement.Conn[0] > -1))
5292  {
5293  Disp->PlotOutput(43, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl90set);
5294  }
5295  else if((TrackElement.SpeedTag == 90) && (TrackElement.Conn[0] == -1))
5296  {
5297  Disp->PlotOutput(44, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl90unset);
5298  }
5299  if((TrackElement.SpeedTag == 91) && (TrackElement.Conn[0] > -1))
5300  {
5301  Disp->PlotOutput(45, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl91set);
5302  }
5303  else if((TrackElement.SpeedTag == 91) && (TrackElement.Conn[0] == -1))
5304  {
5305  Disp->PlotOutput(46, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl91unset);
5306  }
5307  if((TrackElement.SpeedTag == 92) && (TrackElement.Conn[0] > -1))
5308  {
5309  Disp->PlotOutput(47, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl92set);
5310  }
5311  else if((TrackElement.SpeedTag == 92) && (TrackElement.Conn[0] == -1))
5312  {
5313  Disp->PlotOutput(48, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl92unset);
5314  }
5315  if((TrackElement.SpeedTag == 93) && (TrackElement.Conn[0] > -1))
5316  {
5317  Disp->PlotOutput(49, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->bm93set);
5318  }
5319  else if((TrackElement.SpeedTag == 93) && (TrackElement.Conn[0] == -1))
5320  {
5321  Disp->PlotOutput(50, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->bm93unset);
5322  }
5323  if((TrackElement.SpeedTag == 94) && (TrackElement.Conn[0] > -1))
5324  {
5325  Disp->PlotOutput(51, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->bm94set);
5326  }
5327  else if((TrackElement.SpeedTag == 94) && (TrackElement.Conn[0] == -1))
5328  {
5329  Disp->PlotOutput(52, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->bm94unset);
5330  }
5331  if((TrackElement.SpeedTag == 95) && (TrackElement.Conn[0] > -1))
5332  {
5333  Disp->PlotOutput(53, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl95set);
5334  }
5335  else if((TrackElement.SpeedTag == 95) && (TrackElement.Conn[0] == -1))
5336  {
5337  Disp->PlotOutput(54, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl95unset);
5338  }
5339  Utilities->CallLogPop(1101);
5340 }
5341 
5342 // ---------------------------------------------------------------------------
5343 
5344 void TTrack::PlotPoints(int Caller, TTrackElement TrackElement, TDisplay *Disp, bool BothFillets)
5345 {
5346  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotPoints," + TrackElement.LogTrack(2));
5347  if(TrackElement.TrackType != Points)
5348  {
5349  throw Exception("Error, Wrong track type in PlotPoints");
5350  }
5351  Disp->PlotPointBlank(0, TrackElement.HLoc, TrackElement.VLoc); // to get rid of earlier fillet
5352  TrackElement.PlotVariableTrackElement(4, Disp);
5353  if(BothFillets)
5354  {
5355  if(TrackElement.SpeedTag < 28)
5356  {
5357  Disp->PlotOutput(55, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][0]);
5358  Disp->PlotOutput(73, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][1]);
5359  }
5360  else if(TrackElement.SpeedTag < 132)
5361  {
5362  Disp->PlotOutput(56, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][0]);
5363  Disp->PlotOutput(74, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][1]);
5364  }
5365  else
5366  {
5367  Disp->PlotOutput(70, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][0]);
5368  Disp->PlotOutput(71, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][1]);
5369  }
5370  }
5371  else
5372  {
5373  if(TrackElement.SpeedTag < 28)
5374  {
5375  Disp->PlotOutput(75, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
5376  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][TrackElement.Attribute]);
5377  }
5378  else if(TrackElement.SpeedTag < 132)
5379  {
5380  Disp->PlotOutput(76, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
5381  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][TrackElement.Attribute]);
5382  }
5383  else
5384  {
5385  Disp->PlotOutput(72, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
5386  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][TrackElement.Attribute]);
5387  }
5388  }
5389 // replot platform if required
5390  TIMPair IMPair;
5391  bool FoundFlag;
5392 
5393  IMPair = GetVectorPositionsFromInactiveTrackMap(15, TrackElement.HLoc, TrackElement.VLoc, FoundFlag);
5394  if(FoundFlag)
5395  { // only one platform possible at points so only need to plot IMPair.first
5396  TTrackElement PlatElement = InactiveTrackElementAt(89, IMPair.first);
5397  PlatElement.PlotVariableTrackElement(5, Disp); // to plot as striped or non-striped depending on whether named or not
5398  }
5399  Utilities->CallLogPop(519);
5400 }
5401 
5402 // ---------------------------------------------------------------------------
5403 
5404 void TTrack::PlotSignal(int Caller, TTrackElement TrackElement, TDisplay *Disp)
5405 {
5406 // Can't use TrackElement.PlotVariableTrackElement() here as graphic changes depending on signal colour
5407  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSignal," + TrackElement.LogTrack(3));
5408  if(TrackElement.TrackType != SignalPost)
5409  {
5410  throw Exception("Error, Wrong track type in PlotSignal");
5411  }
5412  for(int x = 0; x < 40; x++)
5413  {
5414  if((SigTable[x].SpeedTag == TrackElement.SpeedTag) && (SigTable[x].Attribute == TrackElement.Attribute))
5415  {
5416  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
5417  Disp->PlotSignalBlank(0, TrackElement.HLoc, TrackElement.VLoc, TrackElement.SpeedTag, Utilities->RHSignalFlag);
5418 // in case existing signal is a double yellow
5419  // plot platforms if present
5420 // Graphics::TBitmap* SignalPlatformGraphic;
5421 // if(PlatformOnSignalSide(0, TrackElement.HLoc, TrackElement.VLoc, TrackElement.SpeedTag, SignalPlatformGraphic))
5422 // Above dropped at v2.3.0. Now plot either or both platforms if present regardless of which side they are on. The platforms will
5423 // be consistent with the signal graphic as can't enter an inappropriate platform. The new right hand signal option caused platforms
5424 // to not be plotted with the above function.
5425  PlotSignalPlatforms(0, TrackElement.HLoc, TrackElement.VLoc, Disp); // if no platforms nothing is plotted
5426  // now plot signal (double yellow overwrites most of signal platform if present)
5427  // additions at version 0.6 for other aspects & ground sigs
5428  if(TrackElement.SigAspect == TTrackElement::ThreeAspect)
5429  {
5430  Disp->PlotOutput(117, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTableThreeAspect[x].SigPtr);
5431  }
5432  else if(TrackElement.SigAspect == TTrackElement::TwoAspect)
5433  {
5434  Disp->PlotOutput(118, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTableTwoAspect[x].SigPtr);
5435  }
5436  else if(TrackElement.SigAspect == TTrackElement::GroundSignal)
5437  {
5438  Disp->PlotOutput(119, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTableGroundSignal[x].SigPtr);
5439  }
5440  else // 4 aspect
5441  {
5442  Disp->PlotOutput(58, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTable[x].SigPtr);
5443  }
5444  if((TrackElement.CallingOnSet) && (TrackElement.SigAspect != TTrackElement::GroundSignal))
5445  // normal signal calling on, need to add extra graphic, basic red signal plotted above from SigTable
5446  {
5447  if(TrackElement.SpeedTag == 68)
5448  {
5449  Disp->PlotOutput(59, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm68CallingOn);
5450  }
5451  if(TrackElement.SpeedTag == 69)
5452  {
5453  Disp->PlotOutput(60, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm69CallingOn);
5454  }
5455  if(TrackElement.SpeedTag == 70)
5456  {
5457  Disp->PlotOutput(61, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm70CallingOn);
5458  }
5459  if(TrackElement.SpeedTag == 71)
5460  {
5461  Disp->PlotOutput(62, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm71CallingOn);
5462  }
5463  if(TrackElement.SpeedTag == 72)
5464  {
5465  Disp->PlotOutput(63, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm72CallingOn);
5466  }
5467  if(TrackElement.SpeedTag == 73)
5468  {
5469  Disp->PlotOutput(64, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm73CallingOn);
5470  }
5471  if(TrackElement.SpeedTag == 74)
5472  {
5473  Disp->PlotOutput(65, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm74CallingOn);
5474  }
5475  if(TrackElement.SpeedTag == 75)
5476  {
5477  Disp->PlotOutput(66, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm75CallingOn);
5478  }
5479  }
5480  else if((TrackElement.CallingOnSet) && (TrackElement.SigAspect == TTrackElement::GroundSignal))
5481  // ground signal calling on, need to use normal proceed aspect
5482  {
5483  for(int x = 0; x < 40; x++)
5484  {
5485  if((SigTableGroundSignal[x].SpeedTag == TrackElement.SpeedTag) && (SigTable[x].Attribute == 1)) // use attr 1 for proceed
5486  {
5487  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
5488  Disp->PlotSignalBlank(1, TrackElement.HLoc, TrackElement.VLoc, TrackElement.SpeedTag, Utilities->RHSignalFlag);
5489  // plot special signal platform if present
5490  Graphics::TBitmap* SignalPlatformGraphic;
5491  PlotSignalPlatforms(1, TrackElement.HLoc, TrackElement.VLoc, Disp);
5492  // now plot signal
5493  Disp->PlotOutput(123, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTableGroundSignal[x].SigPtr);
5494  }
5495  }
5496  }
5497  break;
5498  }
5499  }
5500  Utilities->CallLogPop(520);
5501 }
5502 
5503 // ---------------------------------------------------------------------------
5504 
5505 void TTrack::PlotSignalPlatforms(int Caller, int HLoc, int VLoc, TDisplay *Disp)
5506 {
5507  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSignalPlatforms," + AnsiString(HLoc) + "," + AnsiString(VLoc));
5508  bool FoundFlag;
5509  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(13, HLoc, VLoc, FoundFlag);
5510 
5511  if(!FoundFlag)
5512  {
5513  Utilities->CallLogPop(2112);
5514  return;
5515  }
5516  TTrackElement IAElement1 = InactiveTrackElementAt(124, IMPair.first);
5517  TTrackElement IAElement2 = InactiveTrackElementAt(125, IMPair.second);
5518 
5519  // don't want 'else if' for the below as may need to plot 2 platforms
5520  if((IAElement1.SpeedTag == 76) || (IAElement2.SpeedTag == 76)) // top plat
5521  {
5522  if(IAElement1.LocationName == "") // '2' will be same
5523  {
5524  Disp->PlotOutput(239, HLoc * 16, VLoc * 16, RailGraphics->gl76Striped);
5525  }
5526  else
5527  {
5528  Disp->PlotOutput(240, HLoc * 16, VLoc * 16, RailGraphics->gl76);
5529  }
5530  }
5531  if((IAElement1.SpeedTag == 77) || (IAElement2.SpeedTag == 77)) // bot plat
5532  {
5533  if(IAElement1.LocationName == "") // '2' will be same
5534  {
5535  Disp->PlotOutput(241, HLoc * 16, VLoc * 16, RailGraphics->bm77Striped);
5536  }
5537  else
5538  {
5539  Disp->PlotOutput(242, HLoc * 16, VLoc * 16, RailGraphics->bm77);
5540  }
5541  }
5542  if((IAElement1.SpeedTag == 78) || (IAElement2.SpeedTag == 78)) // lh plat
5543  {
5544  if(IAElement1.LocationName == "") // '2' will be same
5545  {
5546  Disp->PlotOutput(243, HLoc * 16, VLoc * 16, RailGraphics->bm78Striped);
5547  }
5548  else
5549  {
5550  Disp->PlotOutput(244, HLoc * 16, VLoc * 16, RailGraphics->bm78);
5551  }
5552  }
5553  if((IAElement1.SpeedTag == 79) || (IAElement2.SpeedTag == 79)) // rh plat
5554  {
5555  if(IAElement1.LocationName == "") // '2' will be same
5556  {
5557  Disp->PlotOutput(245, HLoc * 16, VLoc * 16, RailGraphics->gl79Striped);
5558  }
5559  else
5560  {
5561  Disp->PlotOutput(246, HLoc * 16, VLoc * 16, RailGraphics->gl79);
5562  }
5563  }
5564  Utilities->CallLogPop(2113);
5565 }
5566 
5567 // ---------------------------------------------------------------------------
5568 
5569 void TTrack::SetLinkedLevelCrossingBarrierAttributes(int Caller, int HLoc, int VLoc, int Attr)
5570 {
5571 // Set attrs to 0=closed to trains; 1=open to trains; 3 = changing = closed to trains
5572  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LowerLinkedLevelCrossingBarrierAttributes," + AnsiString(HLoc) + "," +
5573  AnsiString(VLoc));
5574 // find topmost LC, opening them all (to trains) in turn
5575  int UpStep = 0;
5576 
5577  while(IsLCAtHV(0, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
5578  {
5579  SetLCAttributeAtHV(0, HLoc, (VLoc + UpStep), Attr);
5580  UpStep--;
5581  }
5582 // now find bottommost LC, opening them all (to trains) in turn
5583  int DownStep = 1;
5584 
5585  while(IsLCAtHV(1, HLoc, (VLoc + DownStep)))
5586  {
5587  SetLCAttributeAtHV(1, HLoc, (VLoc + DownStep), Attr);
5588  DownStep++;
5589  }
5590 // find leftmost LC, opening them all (to trains) in turn
5591  int LeftStep = 0;
5592 
5593  while(IsLCAtHV(2, (HLoc + LeftStep), VLoc)) // will always find LC at LeftStep == 0
5594  {
5595  SetLCAttributeAtHV(2, (HLoc + LeftStep), VLoc, Attr);
5596  LeftStep--;
5597  }
5598 // now find rightmost LC, opening them all (to trains) in turn
5599  int RightStep = 1;
5600 
5601  while(IsLCAtHV(3, (HLoc + RightStep), VLoc))
5602  {
5603  SetLCAttributeAtHV(3, (HLoc + RightStep), VLoc, Attr);
5604  RightStep++;
5605  }
5606  Utilities->CallLogPop(1915);
5607 }
5608 
5609 // ---------------------------------------------------------------------------
5610 
5611 void TTrack::PlotLoweredLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, bool ConsecSignals, TDisplay *Disp)
5612  // open to trains
5613  // BaseElementSpeedTag: 1 = Horizontal track, 2 = vertical track
5614 {
5615  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotLoweredLinkedLevelCrossingBarriers," + AnsiString(HLoc) + "," +
5616  AnsiString(VLoc));
5617  if(!IsLCAtHV(4, HLoc, VLoc))
5618  {
5619  throw Exception("Error, Wrong track type in PlotAndLowerLevelCrossingBarriers");
5620  }
5621  if((BaseElementSpeedTag != 1) && (BaseElementSpeedTag != 2))
5622  {
5623  throw Exception("Error, Wrong BaseElementSpeedTag value in PlotAndLowerLevelCrossingBarriers");
5624  }
5625 // check for adjacent LCs & if so open (to trains)
5626  if(BaseElementSpeedTag == 1) // hor track element
5627  {
5628  // find topmost LC, opening them all (to trains) in turn
5629  int UpStep = 0;
5630  while(IsLCAtHV(5, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
5631  {
5632  UpStep--;
5633  }
5634  UpStep++;
5635  // now find bottommost LC, opening them all (to trains) in turn
5636  int DownStep = 1;
5637  while(IsLCAtHV(6, HLoc, (VLoc + DownStep)))
5638  {
5639  DownStep++;
5640  }
5641  DownStep--;
5642  // now plot graphics, UpStep is smallest & DownStep largest
5643  // RouteGraphic is the coloured track element, BaseGraphic is non-coloured
5644  // Only need to plot the coloured graphic for the HLoc & VLoc in the vector as that is the route that is causeing the LC to flash
5645  Graphics::TBitmap *RouteGraphic;
5646  if(ConsecSignals)
5647  {
5648  RouteGraphic = RailGraphics->LinkSigRouteGraphicsPtr[0];
5649  }
5650  else
5651  {
5652  RouteGraphic = RailGraphics->LinkNonSigRouteGraphicsPtr[0];
5653  }
5654  Graphics::TBitmap *BaseGraphic = RailGraphics->gl1;
5655 // LinkSigRouteGraphicsPtr[0] hor } pref dir
5656 // LinkSigRouteGraphicsPtr[1] ver }
5657 // LinkNonSigRouteGraphicsPtr[0] hor } non pref dir
5658 // LinkNonSigRouteGraphicsPtr[1] ver }
5659 
5660  if(UpStep == DownStep) // both 0, so just a single track, plot the double graphic, but plot solid bgnd first then track to get rid of earlier graphics
5661  {
5662  Disp->PlotOutput(132, HLoc * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
5663  Disp->PlotOutput(133, HLoc * 16, VLoc * 16, RouteGraphic);
5664  Disp->PlotOutput(134, HLoc * 16, VLoc * 16, RailGraphics->LCBothHor);
5665  }
5666  else if((DownStep - UpStep) == 1) // double track, no need for any plain LC graphics
5667  {
5668  if(UpStep == 0)
5669  {
5670  Disp->PlotOutput(135, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
5671  Disp->PlotOutput(136, HLoc * 16, (VLoc + UpStep) * 16, RouteGraphic);
5672  Disp->PlotOutput(137, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
5673  Disp->PlotOutput(138, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
5674  Disp->PlotOutput(139, HLoc * 16, (VLoc + DownStep) * 16, BaseGraphic);
5675  Disp->PlotOutput(140, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
5676  }
5677  else
5678  {
5679  Disp->PlotOutput(195, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
5680  Disp->PlotOutput(196, HLoc * 16, (VLoc + UpStep) * 16, BaseGraphic);
5681  Disp->PlotOutput(197, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
5682  Disp->PlotOutput(198, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
5683  Disp->PlotOutput(199, HLoc * 16, (VLoc + DownStep) * 16, RouteGraphic);
5684  Disp->PlotOutput(200, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
5685  }
5686  }
5687  else // at least one plain graphic
5688  {
5689  if(UpStep == 0)
5690  {
5691  Disp->PlotOutput(141, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
5692  Disp->PlotOutput(142, HLoc * 16, (VLoc + UpStep) * 16, RouteGraphic);
5693  Disp->PlotOutput(143, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
5694  Disp->PlotOutput(144, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
5695  Disp->PlotOutput(145, HLoc * 16, (VLoc + DownStep) * 16, BaseGraphic);
5696  Disp->PlotOutput(146, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
5697  }
5698  else if(DownStep == 0)
5699  {
5700  Disp->PlotOutput(201, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
5701  Disp->PlotOutput(202, HLoc * 16, (VLoc + UpStep) * 16, BaseGraphic);
5702  Disp->PlotOutput(203, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
5703  Disp->PlotOutput(204, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
5704  Disp->PlotOutput(205, HLoc * 16, (VLoc + DownStep) * 16, RouteGraphic);
5705  Disp->PlotOutput(206, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
5706  }
5707  else
5708  {
5709  Disp->PlotOutput(207, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
5710  Disp->PlotOutput(208, HLoc * 16, (VLoc + UpStep) * 16, BaseGraphic);
5711  Disp->PlotOutput(209, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
5712  Disp->PlotOutput(210, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
5713  Disp->PlotOutput(211, HLoc * 16, (VLoc + DownStep) * 16, BaseGraphic);
5714  Disp->PlotOutput(212, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
5715  }
5716  for(int x = (UpStep + 1); x < DownStep; x++)
5717  {
5718  Disp->PlotOutput(147, HLoc * 16, (VLoc + x) * 16, RailGraphics->bmSolidBgnd);
5719  if(x == 0)
5720  Disp->PlotOutput(148, HLoc * 16, (VLoc + x) * 16, RouteGraphic);
5721  else
5722  Disp->PlotOutput(213, HLoc * 16, (VLoc + x) * 16, BaseGraphic);
5723  Disp->PlotOutput(149, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCPlain);
5724  }
5725  }
5726  Disp->Update();
5727  Utilities->CallLogPop(1958);
5728  return;
5729  }
5730 
5731  else // ver track element
5732  {
5733  // find leftmost LC, opening them all (to trains) in turn
5734  int LStep = 0;
5735  while(IsLCAtHV(7, (HLoc + LStep), VLoc))
5736  {
5737  LStep--;
5738  }
5739  LStep++;
5740  // now find rightmost LC, opening them all (to trains) in turn
5741  int RStep = 1;
5742  while(IsLCAtHV(8, (HLoc + RStep), VLoc))
5743  {
5744  RStep++;
5745  }
5746  RStep--;
5747  // now plot graphics, LStep is smallest & RStep largest
5748  Graphics::TBitmap *RouteGraphic;
5749  if(ConsecSignals)
5750  {
5751  RouteGraphic = RailGraphics->LinkSigRouteGraphicsPtr[1];
5752  }
5753  else
5754  {
5755  RouteGraphic = RailGraphics->LinkNonSigRouteGraphicsPtr[1];
5756  }
5757  Graphics::TBitmap *BaseGraphic = RailGraphics->gl2;
5758 // LinkSigRouteGraphicsPtr[0] hor } pref dir
5759 // LinkSigRouteGraphicsPtr[1] ver }
5760 // LinkNonSigRouteGraphicsPtr[0] hor } non pref dir
5761 // LinkNonSigRouteGraphicsPtr[1] ver }
5762  if(LStep == RStep) // both 0, so just a single track, plot the double graphic, but plot solid bgnd first then track to get rid of earlier graphics
5763  {
5764  Disp->PlotOutput(150, HLoc * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
5765  Disp->PlotOutput(151, HLoc * 16, VLoc * 16, RouteGraphic);
5766  Disp->PlotOutput(152, HLoc * 16, VLoc * 16, RailGraphics->LCBothVer);
5767  }
5768  else if((RStep - LStep) == 1) // double track, no need for any plain LC graphics
5769  {
5770  if(LStep == 0)
5771  {
5772  Disp->PlotOutput(153, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
5773  Disp->PlotOutput(154, (HLoc + LStep) * 16, VLoc * 16, RouteGraphic);
5774  Disp->PlotOutput(155, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
5775  Disp->PlotOutput(156, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
5776  Disp->PlotOutput(157, (HLoc + RStep) * 16, VLoc * 16, BaseGraphic);
5777  Disp->PlotOutput(158, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
5778  }
5779  else
5780  {
5781  Disp->PlotOutput(214, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
5782  Disp->PlotOutput(215, (HLoc + LStep) * 16, VLoc * 16, BaseGraphic);
5783  Disp->PlotOutput(216, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
5784  Disp->PlotOutput(217, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
5785  Disp->PlotOutput(218, (HLoc + RStep) * 16, VLoc * 16, RouteGraphic);
5786  Disp->PlotOutput(219, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
5787  }
5788  }
5789  else // at least one plain graphic
5790  {
5791  if(LStep == 0)
5792  {
5793  Disp->PlotOutput(159, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
5794  Disp->PlotOutput(160, (HLoc + LStep) * 16, VLoc * 16, RouteGraphic);
5795  Disp->PlotOutput(161, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
5796  Disp->PlotOutput(162, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
5797  Disp->PlotOutput(163, (HLoc + RStep) * 16, VLoc * 16, BaseGraphic);
5798  Disp->PlotOutput(164, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
5799  }
5800  else if(RStep == 0)
5801  {
5802  Disp->PlotOutput(220, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
5803  Disp->PlotOutput(221, (HLoc + LStep) * 16, VLoc * 16, BaseGraphic);
5804  Disp->PlotOutput(222, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
5805  Disp->PlotOutput(223, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
5806  Disp->PlotOutput(224, (HLoc + RStep) * 16, VLoc * 16, RouteGraphic);
5807  Disp->PlotOutput(225, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
5808  }
5809  else
5810  {
5811  Disp->PlotOutput(226, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
5812  Disp->PlotOutput(227, (HLoc + LStep) * 16, VLoc * 16, BaseGraphic);
5813  Disp->PlotOutput(228, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
5814  Disp->PlotOutput(229, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
5815  Disp->PlotOutput(230, (HLoc + RStep) * 16, VLoc * 16, BaseGraphic);
5816  Disp->PlotOutput(231, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
5817  }
5818  for(int x = (LStep + 1); x < RStep; x++)
5819  {
5820  Disp->PlotOutput(165, (HLoc + x) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
5821  if(x == 0)
5822  Disp->PlotOutput(166, (HLoc + x) * 16, VLoc * 16, RouteGraphic);
5823  else
5824  Disp->PlotOutput(232, (HLoc + x) * 16, VLoc * 16, BaseGraphic);
5825  Disp->PlotOutput(167, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCPlain);
5826  }
5827  }
5828  Disp->Update();
5829  Utilities->CallLogPop(1896);
5830  return;
5831  }
5832 }
5833 
5834 // ---------------------------------------------------------------------------
5835 
5836 void TTrack::PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp) // open to trains
5837  // BaseElementSpeedTag: 1 = Horizontal track, 2 = vertical track
5838 {
5839  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers," +
5840  AnsiString(HLoc) + "," + AnsiString(VLoc));
5841  if(!IsLCAtHV(29, HLoc, VLoc))
5842  {
5843  throw Exception("Error, Wrong track type in PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers");
5844  }
5845  if((BaseElementSpeedTag != 1) && (BaseElementSpeedTag != 2))
5846  {
5847  throw Exception("Error, Wrong BaseElementSpeedTag value in PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers");
5848  }
5849 // check for adjacent LCs & if so open (to trains)
5850  if(BaseElementSpeedTag == 1) // hor track element
5851  {
5852  // find topmost LC, opening them all (to trains) in turn
5853  int UpStep = 0;
5854  while(IsLCAtHV(30, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
5855  {
5856  UpStep--;
5857  }
5858  UpStep++;
5859  // now find bottommost LC, opening them all (to trains) in turn
5860  int DownStep = 1;
5861  while(IsLCAtHV(31, HLoc, (VLoc + DownStep)))
5862  {
5863  DownStep++;
5864  }
5865  DownStep--;
5866  // now plot graphics, UpStep is smallest & DownStep largest
5867  if(UpStep == DownStep) // both 0, so just a single track, plot the double graphic, but plot solid bgnd first then track to get rid of earlier graphics
5868  {
5869  Disp->PlotOutput(179, HLoc * 16, VLoc * 16, RailGraphics->LCBothHor);
5870  }
5871  else if((DownStep - UpStep) == 1) // double track, no need for any plain LC graphics
5872  {
5873  Disp->PlotOutput(180, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
5874  Disp->PlotOutput(181, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
5875  }
5876  else // at least one plain graphic
5877  {
5878  Disp->PlotOutput(182, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
5879  Disp->PlotOutput(183, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
5880  for(int x = (UpStep + 1); x < DownStep; x++)
5881  {
5882  Disp->PlotOutput(184, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCPlain);
5883  }
5884  }
5885  // set markers
5886  for(int x = UpStep; x <= DownStep; x++)
5887  {
5888  GetInactiveTrackElementFromTrackMap(3, HLoc, (VLoc + x)).TempMarker = true; // plotted
5889  }
5890  Display->Update();
5891  Utilities->CallLogPop(1944);
5892  return;
5893  }
5894 
5895  else // ver track element
5896  {
5897  // find leftmost LC, opening them all (to trains) in turn
5898  int LStep = 0;
5899  while(IsLCAtHV(32, (HLoc + LStep), VLoc))
5900  {
5901  LStep--;
5902  }
5903  LStep++;
5904  // now find rightmost LC, opening them all (to trains) in turn
5905  int RStep = 1;
5906  while(IsLCAtHV(33, (HLoc + RStep), VLoc))
5907  {
5908  RStep++;
5909  }
5910  RStep--;
5911  // now plot graphics, LStep is smallest & RStep largest
5912  if(LStep == RStep) // both 0, so just a single track, plot the double graphic, but plot solid bgnd first then track to get rid of earlier graphics
5913  {
5914  Disp->PlotOutput(185, HLoc * 16, VLoc * 16, RailGraphics->LCBothVer);
5915  }
5916  else if((RStep - LStep) == 1) // double track, no need for any plain LC graphics
5917  {
5918  Disp->PlotOutput(186, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
5919  Disp->PlotOutput(187, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
5920  }
5921  else // at least one plain graphic
5922  {
5923  Disp->PlotOutput(188, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
5924  Disp->PlotOutput(189, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
5925  for(int x = (LStep + 1); x < RStep; x++)
5926  {
5927  Disp->PlotOutput(190, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCPlain);
5928  }
5929  }
5930  // set markers
5931  for(int x = LStep; x <= RStep; x++)
5932  {
5933  GetInactiveTrackElementFromTrackMap(4, (HLoc + x), VLoc).TempMarker = true; // plotted
5934  }
5935  Disp->Update();
5936  Utilities->CallLogPop(1945);
5937  return;
5938  }
5939 }
5940 
5941 // ---------------------------------------------------------------------------
5942 
5943 void TTrack::PlotRaisedLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp) // closed to trains
5944  // BaseElementSpeedTag: 1 = Horizontal track, 2 = vertical track
5945 {
5946  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotRaisedLinkedLevelCrossingBarriers," + AnsiString(HLoc) + "," +
5947  AnsiString(VLoc));
5948  if(!IsLCAtHV(9, HLoc, VLoc))
5949  {
5950  throw Exception("Error, Wrong track type in PlotAndRaiseLevelCrossingBarriers");
5951  }
5952  if((BaseElementSpeedTag != 1) && (BaseElementSpeedTag != 2))
5953  {
5954  throw Exception("Error, Wrong BaseElementSpeedTag value in PlotAndRaiseLevelCrossingBarriers");
5955  }
5956 // check for adjacent LCs & if so close (to trains)
5957  if(BaseElementSpeedTag == 1) // hor track element
5958  {
5959  // find topmost LC, closing them all (to trains) in turn
5960  int UpStep = 0;
5961  while(IsLCAtHV(10, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
5962  {
5963  UpStep--;
5964  }
5965  UpStep++;
5966  // now find bottommost LC, opening them all (to trains) in turn
5967  int DownStep = 1;
5968  while(IsLCAtHV(11, HLoc, (VLoc + DownStep)))
5969  {
5970  DownStep++;
5971  }
5972  DownStep--;
5973  // now plot graphics, UpStep is smallest & DownStep largest
5974  for(int x = UpStep; x < (DownStep + 1); x++)
5975  {
5976  Disp->PlotOutput(168, HLoc * 16, (VLoc + x) * 16, RailGraphics->bmSolidBgnd);
5977  Disp->PlotOutput(169, HLoc * 16, (VLoc + x) * 16, RailGraphics->gl1);
5978  Disp->PlotOutput(170, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCBothVer);
5979  }
5980  Disp->Update();
5981  Utilities->CallLogPop(1959);
5982  return;
5983  }
5984 
5985  else // ver track element
5986  {
5987  // find leftmost LC, closing them all (to trains) in turn
5988  int LStep = 0;
5989  while(IsLCAtHV(12, (HLoc + LStep), VLoc))
5990  {
5991  LStep--;
5992  }
5993  LStep++;
5994  // now find rightmost LC, opening them all (to trains) in turn
5995  int RStep = 1;
5996  while(IsLCAtHV(13, (HLoc + RStep), VLoc))
5997  {
5998  RStep++;
5999  }
6000  RStep--;
6001  // now plot graphics, LStep is smallest & RStep largest
6002  for(int x = LStep; x < (RStep + 1); x++)
6003  {
6004  Disp->PlotOutput(171, (HLoc + x) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6005  Disp->PlotOutput(172, (HLoc + x) * 16, VLoc * 16, RailGraphics->gl2);
6006  Disp->PlotOutput(173, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCBothHor);
6007  }
6008  Disp->Update();
6009  Utilities->CallLogPop(1960);
6010  return;
6011  }
6012 }
6013 
6014 // ---------------------------------------------------------------------------
6015 
6016 void TTrack::PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp)
6017  // closed to trains
6018  // BaseElementSpeedTag: 1 = Horizontal track, 2 = vertical track
6019 {
6020  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers," +
6021  AnsiString(HLoc) + "," + AnsiString(VLoc));
6022  if(!IsLCAtHV(34, HLoc, VLoc))
6023  {
6024  throw Exception("Error, Wrong track type in PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers");
6025  }
6026  if((BaseElementSpeedTag != 1) && (BaseElementSpeedTag != 2))
6027  {
6028  throw Exception("Error, Wrong BaseElementSpeedTag value in PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers");
6029  }
6030  TTrackElement TE;
6031 
6032 // check for adjacent LCs & if so close (to trains)
6033  if(BaseElementSpeedTag == 1) // hor track element
6034  {
6035  // find topmost LC, closing them all (to trains) in turn
6036  int UpStep = 0;
6037  while(IsLCAtHV(35, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
6038  {
6039  UpStep--;
6040  }
6041  UpStep++;
6042  // now find bottommost LC, opening them all (to trains) in turn
6043  int DownStep = 1;
6044  while(IsLCAtHV(36, HLoc, (VLoc + DownStep)))
6045  {
6046  DownStep++;
6047  }
6048  DownStep--;
6049  // now plot graphics, UpStep is smallest & DownStep largest
6050  for(int x = UpStep; x <= DownStep; x++)
6051  {
6052  Disp->PlotOutput(191, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCBothVer);
6053  GetInactiveTrackElementFromTrackMap(1, HLoc, (VLoc + x)).TempMarker = true; // plotted
6054  }
6055  Display->Update();
6056  Utilities->CallLogPop(1946);
6057  return;
6058  }
6059 
6060  else // ver track element
6061  {
6062  // find leftmost LC, closing them all (to trains) in turn
6063  int LStep = 0;
6064  while(IsLCAtHV(37, (HLoc + LStep), VLoc))
6065  {
6066  LStep--;
6067  }
6068  LStep++;
6069  // now find rightmost LC, opening them all (to trains) in turn
6070  int RStep = 1;
6071  while(IsLCAtHV(38, (HLoc + RStep), VLoc))
6072  {
6073  RStep++;
6074  }
6075  RStep--;
6076  // now plot graphics, LStep is smallest & RStep largest
6077  for(int x = LStep; x <= RStep; x++)
6078  {
6079  Disp->PlotOutput(192, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCBothHor);
6080  GetInactiveTrackElementFromTrackMap(2, (HLoc + x), VLoc).TempMarker = true; // plotted
6081  }
6082  Display->Update();
6083  Utilities->CallLogPop(1947);
6084  return;
6085  }
6086 }
6087 
6088 // ---------------------------------------------------------------------------
6089 
6090 void TTrack::PlotLCBaseElementsOnly(int Caller, TBarrierState State, int BaseElementSpeedTag, int HLoc, int VLoc, bool ConsecSignals, TDisplay *Disp)
6091 {
6092  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotBaseElementsOnly," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6093  Graphics::TBitmap *RouteGraphic;
6094  Graphics::TBitmap *BaseGraphic;
6095 
6096  if(BaseElementSpeedTag == 1)
6097  {
6098  if(ConsecSignals)
6099  {
6100  RouteGraphic = RailGraphics->LinkSigRouteGraphicsPtr[0];
6101  }
6102  else
6103  {
6104  RouteGraphic = RailGraphics->LinkNonSigRouteGraphicsPtr[0];
6105  }
6106  BaseGraphic = RailGraphics->gl1;
6107  if(State == Raising)
6108  RouteGraphic = BaseGraphic;
6109  }
6110  else
6111  {
6112  if(ConsecSignals)
6113  {
6114  RouteGraphic = RailGraphics->LinkSigRouteGraphicsPtr[1];
6115  }
6116  else
6117  {
6118  RouteGraphic = RailGraphics->LinkNonSigRouteGraphicsPtr[1];
6119  }
6120  BaseGraphic = RailGraphics->gl2;
6121  if(State == Raising)
6122  RouteGraphic = BaseGraphic;
6123  }
6124  int UpStep = 0;
6125 
6126  while(IsLCAtHV(14, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
6127  {
6128  Disp->PlotOutput(174, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6129  if(UpStep == 0)
6130  Disp->PlotOutput(175, HLoc * 16, (VLoc + UpStep) * 16, RouteGraphic);
6131  else
6132  Disp->PlotOutput(234, HLoc * 16, (VLoc + UpStep) * 16, BaseGraphic);
6133  UpStep--;
6134  }
6135 // now find bottommost LC, opening them all (to trains) in turn
6136  int DownStep = 1;
6137 
6138  while(IsLCAtHV(15, HLoc, (VLoc + DownStep)))
6139  {
6140  Disp->PlotOutput(176, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
6141  Disp->PlotOutput(177, HLoc * 16, (VLoc + DownStep) * 16, BaseGraphic);
6142  DownStep++;
6143  }
6144  int LeftStep = 0;
6145 
6146  while(IsLCAtHV(16, (HLoc + LeftStep), VLoc)) // will always find LC at LeftStep == 0
6147  {
6148  Disp->PlotOutput(233, (HLoc + LeftStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6149  if(LeftStep == 0)
6150  Disp->PlotOutput(235, (HLoc + LeftStep) * 16, VLoc * 16, RouteGraphic);
6151  else
6152  Disp->PlotOutput(236, (HLoc + LeftStep) * 16, VLoc * 16, BaseGraphic);
6153  LeftStep--;
6154  }
6155 // now find rightmost LC, opening them all (to trains) in turn
6156  int RightStep = 1;
6157 
6158  while(IsLCAtHV(17, (HLoc + RightStep), VLoc))
6159  {
6160  Disp->PlotOutput(237, (HLoc + RightStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6161  Disp->PlotOutput(238, (HLoc + RightStep) * 16, VLoc * 16, BaseGraphic);
6162  RightStep++;
6163  }
6164  Disp->Update();
6165  Utilities->CallLogPop(1914);
6166 }
6167 
6168 // ---------------------------------------------------------------------------
6169 
6170 bool TTrack::IsLCBarrierDownAtHV(int Caller, int HLoc, int VLoc) // returns true only if fully down
6171 {
6172 // return false for no LC there, flashing or a closed (to trains) LC
6173  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsLCBarrierDownAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6174  bool FoundFlag;
6175  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(21, HLoc, VLoc, FoundFlag);
6176 
6177  if(!FoundFlag)
6178  {
6179  Utilities->CallLogPop(1898);
6180  return false;
6181  }
6182  if(InactiveTrackElementAt(100, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
6183  {
6184  Utilities->CallLogPop(1899);
6185  return false;
6186  }
6187  if(InactiveTrackElementAt(103, IMPair.first).Attribute == 1)
6188  {
6189  Utilities->CallLogPop(1900);
6190  return true;
6191  }
6192  Utilities->CallLogPop(1901);
6193  return false;
6194 }
6195 
6196 // ---------------------------------------------------------------------------
6197 
6198 bool TTrack::IsLCBarrierUpAtHV(int Caller, int HLoc, int VLoc) // returns true only if fully up
6199 {
6200 // return false for no LC there, flashing LC or open (to trains) LC
6201  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsBarrierUpLCAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6202  bool FoundFlag;
6203  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(24, HLoc, VLoc, FoundFlag);
6204 
6205  if(!FoundFlag)
6206  {
6207  Utilities->CallLogPop(1922);
6208  return false;
6209  }
6210  if(InactiveTrackElementAt(110, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
6211  {
6212  Utilities->CallLogPop(1923);
6213  return false;
6214  }
6215  if(InactiveTrackElementAt(111, IMPair.first).Attribute == 0)
6216  {
6217  Utilities->CallLogPop(1924);
6218  return true;
6219  }
6220  Utilities->CallLogPop(1925);
6221  return false;
6222 }
6223 
6224 // ---------------------------------------------------------------------------
6225 
6226 bool TTrack::IsLCBarrierFlashingAtHV(int Caller, int HLoc, int VLoc)
6227 {
6228 // return true for barrier in process of moving
6229  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsBarrierFlashingAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6230  bool FoundFlag;
6231  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(25, HLoc, VLoc, FoundFlag);
6232 
6233  if(!FoundFlag)
6234  {
6235  Utilities->CallLogPop(1918);
6236  return false;
6237  }
6238  if(InactiveTrackElementAt(112, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
6239  {
6240  Utilities->CallLogPop(1919);
6241  return false;
6242  }
6243  if(InactiveTrackElementAt(113, IMPair.first).Attribute == 2)
6244  {
6245  Utilities->CallLogPop(1920);
6246  return true;
6247  }
6248  Utilities->CallLogPop(1921);
6249  return false;
6250 }
6251 
6252 // ---------------------------------------------------------------------------
6253 
6254 bool TTrack::IsLCAtHV(int Caller, int HLoc, int VLoc)
6255 {
6256 // return true for an LC at H&V
6257  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsLCAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6258  bool FoundFlag;
6259  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(22, HLoc, VLoc, FoundFlag);
6260 
6261  if(!FoundFlag)
6262  {
6263  Utilities->CallLogPop(1902);
6264  return false;
6265  }
6266  if(InactiveTrackElementAt(101, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
6267  {
6268  Utilities->CallLogPop(1903);
6269  return false;
6270  }
6271  Utilities->CallLogPop(1904);
6272  return true;
6273 }
6274 
6275 // ---------------------------------------------------------------------------
6276 
6277 void TTrack::SetLCAttributeAtHV(int Caller, int HLoc, int VLoc, int Attr)
6278 {
6279  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLCAttributeAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
6280  AnsiString(Attr));
6281  bool FoundFlag;
6282  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(23, HLoc, VLoc, FoundFlag);
6283 
6284  if(!FoundFlag)
6285  {
6286  throw Exception("Element not found in LowerLCBarriersAtHV " + AnsiString(HLoc) + "," + AnsiString(VLoc));
6287  }
6288  if(InactiveTrackElementAt(102, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
6289  {
6290  throw Exception("Element not a level crossing in LowerLCBarriersAtHV " + AnsiString(HLoc) + "," + AnsiString(VLoc));
6291  }
6292  InactiveTrackElementAt(104, IMPair.first).Attribute = Attr;
6293  Utilities->CallLogPop(1905);
6294  return;
6295 }
6296 
6297 // ---------------------------------------------------------------------------
6298 
6300 {
6301  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetLevelCrossings");
6302  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
6303  {
6304  TTrackElement InactiveTrackElement = InactiveTrackVector.at(x);
6305  if(InactiveTrackElement.TrackType == LevelCrossing)
6306  {
6307  InactiveTrackVector.at(x).Attribute = 0;
6308  // though this only resets the attributes the LC will display correctly when call Clearand.. in BaseMode
6309  }
6310  }
6311  Utilities->CallLogPop(1913);
6312  return;
6313 }
6314 
6315 // ---------------------------------------------------------------------------
6316 
6317 bool TTrack::AnyLinkedLevelCrossingElementsWithRoutesOrTrains(int Caller, int HLoc, int VLoc, bool &TrainPresent)
6318 {
6319 // return true if there is either a route set on any element or a train on any element
6320  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AnyLinkedLevelCrossingElementsWithRoutesOrTrains," + AnsiString(HLoc) +
6321  "," + AnsiString(VLoc));
6322 
6323  THVPair TrackMapKeyPair;
6324  TTrack::TTrackMapIterator TrackMapPtr;
6325  int DummyRouteNumber;
6326 
6327  TrainPresent = false;
6328 // find topmost LC, checking each for routes & trains
6329  int UpStep = 0;
6330 
6331  while(IsLCAtHV(25, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
6332  {
6333  TrackMapKeyPair.first = HLoc;
6334  TrackMapKeyPair.second = VLoc + UpStep;
6335  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
6336  if(AllRoutes->GetRouteTypeAndNumber(20, TrackMapPtr->second, 0, DummyRouteNumber) != TAllRoutes::NoRoute)
6337  // use 0 for LinkPos, only 1 track element so 0 or 1 would be OK
6338  {
6339  Utilities->CallLogPop(1932);
6340  return true;
6341  }
6342  if(TrackElementAt(867, TrackMapPtr->second).TrainIDOnElement != -1)
6343  {
6344  TrainPresent = true;
6345  Utilities->CallLogPop(1933);
6346  return true;
6347  }
6348  UpStep--;
6349  }
6350 // now find bottommost LC, opening them all (to trains) in turn
6351  int DownStep = 1;
6352 
6353  while(IsLCAtHV(26, HLoc, (VLoc + DownStep)))
6354  {
6355  TrackMapKeyPair.first = HLoc;
6356  TrackMapKeyPair.second = VLoc + DownStep;
6357  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
6358  if(AllRoutes->GetRouteTypeAndNumber(21, TrackMapPtr->second, 0, DummyRouteNumber) != TAllRoutes::NoRoute)
6359  // use 0 for LinkPos, only 1 track element so 0 or 1 would be OK
6360  {
6361  Utilities->CallLogPop(1934);
6362  return true;
6363  }
6364  if(TrackElementAt(868, TrackMapPtr->second).TrainIDOnElement != -1)
6365  {
6366  TrainPresent = true;
6367  Utilities->CallLogPop(1935);
6368  return true;
6369  }
6370  DownStep++;
6371  }
6372 // find leftmost LC
6373  int LeftStep = 0;
6374 
6375  while(IsLCAtHV(27, (HLoc + LeftStep), VLoc)) // will always find LC at LeftStep == 0
6376  {
6377  TrackMapKeyPair.first = HLoc + LeftStep;
6378  TrackMapKeyPair.second = VLoc;
6379  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
6380  if(AllRoutes->GetRouteTypeAndNumber(22, TrackMapPtr->second, 0, DummyRouteNumber) != TAllRoutes::NoRoute)
6381  // use 0 for LinkPos, only 1 track element so 0 or 1 would be OK
6382  {
6383  Utilities->CallLogPop(1936);
6384  return true;
6385  }
6386  if(TrackElementAt(869, TrackMapPtr->second).TrainIDOnElement != -1)
6387  {
6388  TrainPresent = true;
6389  Utilities->CallLogPop(1937);
6390  return true;
6391  }
6392  LeftStep--;
6393  }
6394 // now find rightmost LC, opening them all (to trains) in turn
6395  int RightStep = 1;
6396 
6397  while(IsLCAtHV(28, (HLoc + RightStep), VLoc))
6398  {
6399  TrackMapKeyPair.first = HLoc + RightStep;
6400  TrackMapKeyPair.second = VLoc;
6401  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
6402  if(AllRoutes->GetRouteTypeAndNumber(23, TrackMapPtr->second, 0, DummyRouteNumber) != TAllRoutes::NoRoute)
6403  // use 0 for LinkPos, only 1 track element so 0 or 1 would be OK
6404  {
6405  Utilities->CallLogPop(1938);
6406  return true;
6407  }
6408  if(TrackElementAt(870, TrackMapPtr->second).TrainIDOnElement != -1)
6409  {
6410  TrainPresent = true;
6411  Utilities->CallLogPop(1939);
6412  return true;
6413  }
6414  RightStep++;
6415  }
6416  Utilities->CallLogPop(1940);
6417  return false;
6418 }
6419 
6420 // ---------------------------------------------------------------------------
6421 
6422 Graphics::TBitmap *TTrack::GetFilletGraphic(int Caller, TTrackElement TrackElement)
6423 {
6424  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFilletGraphic," + TrackElement.LogTrack(4));
6425  if(TrackElement.TrackType != Points)
6426  {
6427  throw Exception("Error, Wrong track type in GetFilletGraphic");
6428  }
6429  if(TrackElement.SpeedTag < 28)
6430  {
6431  Utilities->CallLogPop(521);
6432  return RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][TrackElement.Attribute];
6433  }
6434  else if(TrackElement.SpeedTag < 132)
6435  {
6436  Utilities->CallLogPop(522);
6437 // Utilities->CallLogPop callers 523 to 534 inc used to test pop failure
6438  return RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][TrackElement.Attribute];
6439  }
6440  else
6441  {
6442  Utilities->CallLogPop(1537);
6443  return RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][TrackElement.Attribute];
6444  }
6445 }
6446 
6447 // ---------------------------------------------------------------------------
6448 
6450 {
6451  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetAllTrainIDElements");
6452  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
6453  {
6454  TrackVector.at(x).TrainIDOnElement = -1;
6455  TrackVector.at(x).TrainIDOnBridgeTrackPos01 = -1;
6456  TrackVector.at(x).TrainIDOnBridgeTrackPos23 = -1;
6457  }
6458  Utilities->CallLogPop(1342);
6459 }
6460 
6461 // ---------------------------------------------------------------------------
6462 
6463 void TTrack::GetTrackLocsFromScreenPos(int Caller, int &HLoc, int &VLoc, int ScreenPosH, int ScreenPosV)
6464 /*
6465  Converts the screen position to the true (without offsets) HLoc, VLoc 16 x 16 square that the screen position lies within
6466 */
6467 {
6468  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackLocsFromScreenPos," + AnsiString(ScreenPosH) + "," +
6469  AnsiString(ScreenPosV));
6470  HLoc = div(ScreenPosH, 16).quot + Display->DisplayOffsetH;
6471  VLoc = div(ScreenPosV, 16).quot + Display->DisplayOffsetV;
6472 // Utilities->CallLogPop callers 523 to 534 inc used to test pop failure
6473  Utilities->CallLogPop(535);
6474 }
6475 
6476 // ---------------------------------------------------------------------------
6477 
6478 void TTrack::GetTruePositionsFromScreenPos(int Caller, int &HPos, int &VPos, int ScreenPosH, int ScreenPosV)
6479 /*
6480  Converts the screen position to the true (without offsets) position
6481 */
6482 {
6483  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTruePositionsFromScreenPos," + AnsiString(ScreenPosH) + "," +
6484  AnsiString(ScreenPosV));
6485  HPos = ScreenPosH + (Display->DisplayOffsetH * 16);
6486  VPos = ScreenPosV + (Display->DisplayOffsetV * 16);
6487  Utilities->CallLogPop(536);
6488 }
6489 
6490 // ---------------------------------------------------------------------------
6491 
6492 void TTrack::GetScreenPositionsFromTruePos(int Caller, int &ScreenPosH, int &ScreenPosV, int HPosTrue, int VPosTrue)
6493 {
6494  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetScreenPositionsFromTruePos," + AnsiString(HPosTrue) + "," +
6495  AnsiString(VPosTrue));
6496  ScreenPosH = HPosTrue - (Display->DisplayOffsetH * 16);
6497  ScreenPosV = VPosTrue - (Display->DisplayOffsetV * 16);
6498  Utilities->CallLogPop(537);
6499 }
6500 
6501 // ---------------------------------------------------------------------------
6502 
6503 void TTrack::CheckMapAndTrack(int Caller) // test
6504 {
6505  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckMapAndTrack");
6506  int Zeroes = 0;
6507  bool FoundFlag;
6508 
6509  for(unsigned int a = 0; a < TrackVector.size(); a++)
6510  {
6511  TTrackElement CheckElement = Track->TrackVector.at(a);
6512  if(CheckElement.SpeedTag == 0)
6513  {
6514  Zeroes++; // zeroed elements not saved in map
6515  }
6516  else
6517  {
6518  int MapVecPos = GetVectorPositionFromTrackMap(16, CheckElement.HLoc, CheckElement.VLoc, FoundFlag);
6519  if(!FoundFlag)
6520  {
6521  throw Exception("CheckMapAndTrack Error - failed to find HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" + (AnsiString)CheckElement.VLoc +
6522  " in TrackMap, Caller=" + (AnsiString)Caller);
6523  }
6524  if(MapVecPos != (int)a)
6525  {
6526  throw Exception("CheckMapAndTrack Error - MapVectorPosition failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
6527  (AnsiString)CheckElement.VLoc + " Map value=" + (AnsiString)MapVecPos + " TrackVectorPos value=" + (AnsiString)a + " Caller=" +
6528  (AnsiString)Caller);
6529  }
6530  }
6531  }
6532  if(TrackVector.size() != (TrackMap.size() + Zeroes))
6533  {
6534  throw Exception("CheckMapAndTrack Error - Map Size=" + (AnsiString)TrackVector.size() + " TrackVectorSize=" + (AnsiString)TrackVector.size() +
6535  " Caller=" + (AnsiString)Caller);
6536  }
6537  Utilities->CallLogPop(538);
6538  return;
6539 }
6540 
6541 // ---------------------------------------------------------------------------
6542 
6543 void TTrack::CheckMapAndInactiveTrack(int Caller) // test
6544 {
6545  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckMapAndInactiveTrack");
6546  bool FoundFlag;
6547  TIMPair InactivePair;
6548 
6549  for(unsigned int a = 0; a < InactiveTrackVector.size(); a++)
6550  {
6551  TTrackElement CheckElement = Track->InactiveTrackVector.at(a);
6552  InactivePair = GetVectorPositionsFromInactiveTrackMap(7, CheckElement.HLoc, CheckElement.VLoc, FoundFlag);
6553  if(!FoundFlag)
6554  {
6555  throw Exception("CheckMapAndInactiveTrack Error - failed to find HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" + (AnsiString)CheckElement.VLoc +
6556  " in InactiveMap, Caller=" + (AnsiString)Caller);
6557  }
6558  if((InactivePair.first != a) && (InactivePair.second != a))
6559  {
6560  throw Exception("CheckMapAndInactiveTrack Error - InactiveMapVectorPosition failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
6561  (AnsiString)CheckElement.VLoc + " Inactive Map values=" + (AnsiString)InactivePair.first + " and " + (AnsiString)InactivePair.second +
6562  " InactiveTrackVectorPos value=" + (AnsiString)a + " Caller=" + (AnsiString)Caller);
6563  }
6564  }
6565  if(InactiveTrackVector.size() != InactiveTrack2MultiMap.size())
6566  {
6567  throw Exception("CheckMapAndInactiveTrack Error - Map Size=" + (AnsiString)TrackVector.size() + " TrackVectorSize=" + (AnsiString)TrackVector.size() +
6568  " Caller=" + (AnsiString)Caller);
6569  }
6570  Utilities->CallLogPop(539);
6571 }
6572 
6573 // ---------------------------------------------------------------------------
6574 
6575 void TTrack::CheckGapMap(int Caller) // test
6576 {
6577  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckGapMap");
6578  int Position1, Position2;
6579  TTrackElement TrackElement1, TrackElement2;
6580  TGapMapIterator GapMapPtr;
6581 
6582  if(!GapMap.empty())
6583  {
6584  for(GapMapPtr = GapMap.begin(); GapMapPtr != GapMap.end(); GapMapPtr++)
6585  {
6586  int HLoc1 = GapMapPtr->first.first;
6587  int VLoc1 = GapMapPtr->first.second;
6588  int HLoc2 = GapMapPtr->second.first;
6589  int VLoc2 = GapMapPtr->second.second;
6590  if(!FindNonPlatformMatch(14, HLoc1, VLoc1, Position1, TrackElement1))
6591  {
6592  throw Exception("Failed to find H & V for gap1, GapMap in error");
6593  }
6594  if(!FindNonPlatformMatch(15, HLoc2, VLoc2, Position2, TrackElement2))
6595  {
6596  throw Exception("Failed to find H & V for gap2, GapMap in error");
6597  }
6598  if(TrackElementAt(17, Position1).TrackType != GapJump)
6599  {
6600  throw Exception("Element at Pos1 not a gap, GapMap in error");
6601  }
6602  if(TrackElementAt(18, Position2).TrackType != GapJump)
6603  {
6604  throw Exception("Element at Pos2 not a gap, GapMap in error");
6605  }
6606  }
6607  }
6608  unsigned int GapCount = 0;
6609 
6610  for(unsigned int a = 0; a < TrackVector.size(); a++)
6611  {
6612  TTrackElement CheckElement = Track->TrackVector.at(a);
6613  if(CheckElement.TrackType == GapJump)
6614  GapCount++;
6615  }
6616  if((GapMap.size() * 2) != GapCount)
6617  {
6618  throw Exception("GapMap Error - Map Size * 2 =" + (AnsiString)(GapMap.size() * 2) + " GapCount=" + (AnsiString)GapCount + " Caller=" +
6619  (AnsiString)Caller);
6620  }
6621  Utilities->CallLogPop(540);
6622 }
6623 
6624 // ---------------------------------------------------------------------------
6625 
6626 void TTrack::SetElementID(int Caller, TTrackElement &TrackElement)
6627 {
6628  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetElementID," + TrackElement.LogTrack(5));
6629  if((TrackElement.HLoc == -2000000000) || (TrackElement.VLoc == -2000000000))
6630  {
6631  if(TrackFinished)
6632  {
6633  throw Exception("Error - TrackFinished with erase element still present");
6634  }
6635  Utilities->CallLogPop(541);
6636  return; // erased element, can't set ID
6637  }
6638  AnsiString IDString;
6639 
6640  if(TrackElement.HLoc < 0)
6641  IDString = "N" + AnsiString(abs(TrackElement.HLoc)) + "-";
6642  else
6643  IDString = AnsiString(TrackElement.HLoc) + "-";
6644  if(TrackElement.VLoc < 0)
6645  IDString += "N" + AnsiString(abs(TrackElement.VLoc));
6646  else
6647  IDString += AnsiString(TrackElement.VLoc);
6648  TrackElement.ElementID = IDString;
6649  Utilities->CallLogPop(542);
6650 }
6651 
6652 // ---------------------------------------------------------------------------
6653 
6654 int TTrack::GetTrackVectorPositionFromString(int Caller, AnsiString String, bool GiveMessages)
6655 {
6656 // e.g. "8-13", "00008-13", "N43-N127", etc
6657  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackVectorPositionFromString, + String");
6658  int DelimPos;
6659 
6660  for(int x = 1; x < String.Length() + 1; x++)
6661  {
6662  if(String.IsDelimiter("-", x))
6663  {
6664  DelimPos = x;
6665  break;
6666  }
6667  if(x == String.Length())
6668  {
6669  if(GiveMessages)
6670  ShowMessage("Error in track element identifier: <" + String + "> - no delimiter");
6671  Utilities->CallLogPop(543);
6672  return -1;
6673  }
6674  }
6675  if(DelimPos == 1)
6676  {
6677  if(GiveMessages)
6678  ShowMessage("Error in track element identifier: <" + String + "> - No Horizontal value");
6679  Utilities->CallLogPop(544);
6680  return -1;
6681  }
6682  if(DelimPos == String.Length())
6683  {
6684  if(GiveMessages)
6685  ShowMessage("Error in track element identifier <" + String + "> - No Vertical value");
6686  Utilities->CallLogPop(545);
6687  return -1;
6688  }
6689  if((String[String.Length()] < '0') || (String[String.Length()] > '9'))
6690  {
6691  if(GiveMessages)
6692  ShowMessage("Error in track element identifier <" + String + "> - Last value is not a number");
6693  Utilities->CallLogPop(1508);
6694  return -1;
6695  }
6696  int HLoc, VLoc;
6697 
6698  if(String.SubString(1, 1) != "N")
6699  {
6700  for(int x = 1; x < DelimPos; x++)
6701  {
6702  if((String.SubString(x, 1) < "0") || (String.SubString(x, 1) > "9"))
6703  {
6704  if(GiveMessages)
6705  ShowMessage("Invalid character in Horizontal value in track element identifier: <" + String + ">");
6706  Utilities->CallLogPop(546);
6707  return -1;
6708  }
6709  }
6710  }
6711  if(String.SubString(1, 1) == "N")
6712  {
6713  for(int x = 2; x < DelimPos; x++)
6714  {
6715  if((String.SubString(x, 1) < "0") || (String.SubString(x, 1) > "9"))
6716  {
6717  if(GiveMessages)
6718  ShowMessage("Invalid character in Horizontal value in track element identifier: <" + String + ">");
6719  Utilities->CallLogPop(763);
6720  return -1;
6721  }
6722  }
6723  }
6724  if(String.SubString(1, 1) == "N")
6725  HLoc = -(String.SubString(2, DelimPos - 2).ToInt());
6726  else
6727  HLoc = String.SubString(1, DelimPos - 1).ToInt();
6728 
6729  if(String.SubString(DelimPos + 1, 1) != "N")
6730  {
6731  for(int x = DelimPos + 1; x < String.Length() + 1; x++)
6732  {
6733  if((String.SubString(x, 1) < "0") || (String.SubString(x, 1) > "9"))
6734  {
6735  if(GiveMessages)
6736  ShowMessage("Invalid character in Vertical value in track element identifier: <" + String + ">");
6737  Utilities->CallLogPop(547);
6738  return -1;
6739  }
6740  }
6741  }
6742  if(String.SubString(DelimPos + 1, 1) == "N")
6743  {
6744  for(int x = DelimPos + 2; x < String.Length() + 1; x++)
6745  {
6746  if((String.SubString(x, 1) < "0") || (String.SubString(x, 1) > "9"))
6747  {
6748  if(GiveMessages)
6749  ShowMessage("Invalid character in Vertical value in track element identifier: <" + String + ">");
6750  Utilities->CallLogPop(764);
6751  return -1;
6752  }
6753  }
6754  }
6755  if(String.SubString(DelimPos + 1, 1) == "N")
6756  VLoc = -(String.SubString(DelimPos + 2, String.Length() - DelimPos - 1).ToInt());
6757  else
6758  VLoc = String.SubString(DelimPos + 1, String.Length() - DelimPos).ToInt();
6759 
6760  THVPair HVPair(HLoc, VLoc);
6761  TTrackMapIterator TrackMapPtr;
6762 
6763  TrackMapPtr = TrackMap.find(HVPair);
6764  if(TrackMapPtr == TrackMap.end())
6765  {
6766  if(GiveMessages)
6767  ShowMessage("No track element corresponding to track element identifier: <" + String + ">");
6768  Utilities->CallLogPop(548);
6769  return -1;
6770  }
6771  Utilities->CallLogPop(549);
6772  return TrackMapPtr->second;
6773 }
6774 
6775 // ---------------------------------------------------------------------------
6776 
6777 bool TTrack::CheckFootCrossingLinks(int Caller, TTrackElement &TrackElement)
6778 /*
6779  True for linked properly at both ends
6780 */
6781 {
6782  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckFootCrossingLinks," + AnsiString(TrackElement.HLoc) + "," +
6783  AnsiString(TrackElement.VLoc) + "," + AnsiString(TrackElement.SpeedTag));
6784  int HLoc = TrackElement.HLoc;
6785  int VLoc = TrackElement.VLoc;
6786 
6787  if((TrackElement.SpeedTag != 129) && (TrackElement.SpeedTag != 130) && (TrackElement.SpeedTag != 145) && (TrackElement.SpeedTag != 146))
6788  {
6789  Utilities->CallLogPop(1821);
6790  return false;
6791  }
6792  if(TrackElement.SpeedTag == 129) // vertical footbridge
6793  {
6794  // check top connection
6795  if(!(InactiveMapCheck(1, HLoc, VLoc, 76) // top plat
6796  || InactiveMapCheck(2, HLoc, VLoc - 1, 96) // concourse
6797  || InactiveMapCheck(3, HLoc, VLoc - 1, 77) // bot plat
6798  || ActiveMapCheck(4, HLoc, VLoc - 1, 129))) // vert footbridge
6799  {
6800  Utilities->CallLogPop(550);
6801  return false;
6802  }
6803  // check bottom connection
6804  else if(!(InactiveMapCheck(4, HLoc, VLoc, 77) // bot plat
6805  || InactiveMapCheck(5, HLoc, VLoc + 1, 96) // concourse
6806  || InactiveMapCheck(6, HLoc, VLoc + 1, 76) // top plat
6807  || ActiveMapCheck(1, HLoc, VLoc + 1, 129))) // vert footbridge
6808  {
6809  Utilities->CallLogPop(551);
6810  return false;
6811  }
6812  }
6813  if(TrackElement.SpeedTag == 145) // vertical underpass
6814  {
6815  // check top connection
6816  if(!(InactiveMapCheck(13, HLoc, VLoc, 76) // top plat
6817  || InactiveMapCheck(14, HLoc, VLoc - 1, 96) // concourse
6818  || InactiveMapCheck(15, HLoc, VLoc - 1, 77) // bot plat
6819  || ActiveMapCheck(5, HLoc, VLoc - 1, 145))) // vert u'pass
6820  {
6821  Utilities->CallLogPop(2114);
6822  return false;
6823  }
6824  // check bottom connection
6825  else if(!(InactiveMapCheck(16, HLoc, VLoc, 77) // bot plat
6826  || InactiveMapCheck(17, HLoc, VLoc + 1, 96) // concourse
6827  || InactiveMapCheck(18, HLoc, VLoc + 1, 76) // top plat
6828  || ActiveMapCheck(6, HLoc, VLoc + 1, 145))) // vert u'pass
6829  {
6830  Utilities->CallLogPop(2115);
6831  return false;
6832  }
6833  }
6834  if(TrackElement.SpeedTag == 130) // hor footbridge
6835  {
6836  // check left connection
6837  if(!(InactiveMapCheck(19, HLoc, VLoc, 78) // left plat
6838  || InactiveMapCheck(20, HLoc - 1, VLoc, 96) // concourse
6839  || InactiveMapCheck(21, HLoc - 1, VLoc, 79) // right plat
6840  || ActiveMapCheck(2, HLoc - 1, VLoc, 130))) // hor footbridge
6841  {
6842  Utilities->CallLogPop(552);
6843  return false;
6844  }
6845  // check right connection
6846  else if(!(InactiveMapCheck(22, HLoc, VLoc, 79) // right plat
6847  || InactiveMapCheck(23, HLoc + 1, VLoc, 96) // concourse
6848  || InactiveMapCheck(24, HLoc + 1, VLoc, 78) // left plat
6849  || ActiveMapCheck(3, HLoc + 1, VLoc, 130))) // hor footbridge
6850  {
6851  Utilities->CallLogPop(553);
6852  return false;
6853  }
6854  }
6855  if(TrackElement.SpeedTag == 146) // hor u'pass
6856  {
6857  // check left connection
6858  if(!(InactiveMapCheck(7, HLoc, VLoc, 78) // left plat
6859  || InactiveMapCheck(8, HLoc - 1, VLoc, 96) // concourse
6860  || InactiveMapCheck(9, HLoc - 1, VLoc, 79) // right plat
6861  || ActiveMapCheck(7, HLoc - 1, VLoc, 146))) // hor u'pass
6862  {
6863  Utilities->CallLogPop(2116);
6864  return false;
6865  }
6866  // check right connection
6867  else if(!(InactiveMapCheck(10, HLoc, VLoc, 79) // right plat
6868  || InactiveMapCheck(11, HLoc + 1, VLoc, 96) // concourse
6869  || InactiveMapCheck(12, HLoc + 1, VLoc, 78) // left plat
6870  || ActiveMapCheck(8, HLoc + 1, VLoc, 146))) // hor u'pass
6871  {
6872  Utilities->CallLogPop(2117);
6873  return false;
6874  }
6875  }
6876  Utilities->CallLogPop(554);
6877  return true;
6878 }
6879 
6880 // ---------------------------------------------------------------------------
6881 
6882 bool TTrack::InactiveMapCheck(int Caller, int HLoc, int VLoc, int SpeedTag)
6883 /*
6884  return true if the SpeedTag present in the map at H & V
6885 */
6886 {
6887  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",InactiveMapCheck," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
6888  AnsiString(SpeedTag));
6889  if(InactiveTrack2MultiMap.empty())
6890  {
6891  Utilities->CallLogPop(555);
6892  return false;
6893  }
6894  THVPair HVPair(HLoc, VLoc);
6896  TInactiveTrack2MultiMapIterator HVIt1 = IMEnd, HVIt2 = IMEnd;
6897  TInactiveTrackRange HVRange = InactiveTrack2MultiMap.equal_range(HVPair);
6898 
6899  if(HVRange.first == HVRange.second)
6900  {
6901  Utilities->CallLogPop(556);
6902  return false;
6903  }
6904  else
6905  HVIt1 = HVRange.first;
6906  TTrackElement Temp1, Temp2; // test
6907 
6908  Temp1 = InactiveTrackElementAt(8, HVIt1->second); // test
6909  if(--HVRange.second != HVRange.first)
6910  {
6911  HVIt2 = HVRange.second;
6912  Temp2 = InactiveTrackElementAt(9, HVIt2->second); // test
6913  }
6914  if((InactiveTrackElementAt(10, HVIt1->second).SpeedTag == SpeedTag) || ((HVIt2 != IMEnd) && (InactiveTrackElementAt(11,
6915  HVIt2->second).SpeedTag == SpeedTag)))
6916  {
6917  Utilities->CallLogPop(557);
6918  return true;
6919  }
6920  else
6921  {
6922  Utilities->CallLogPop(558);
6923  return false;
6924  }
6925 }
6926 
6927 // ---------------------------------------------------------------------------
6928 
6929 bool TTrack::ActiveMapCheck(int Caller, int HLoc, int VLoc, int SpeedTag)
6930 /*
6931  return true if the SpeedTag present in the map at H & V
6932 */
6933 {
6934  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ActiveMapCheck," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
6935  AnsiString(SpeedTag));
6936  if(TrackMap.empty())
6937  {
6938  Utilities->CallLogPop(559);
6939  return false;
6940  }
6941  THVPair HVPair(HLoc, VLoc);
6942  TTrackMapIterator End = TrackMap.end();
6943  TTrackMapIterator It = End;
6944 
6945  It = TrackMap.find(HVPair);
6946  if((It != End) && (TrackElementAt(19, It->second).SpeedTag == SpeedTag))
6947  {
6948  Utilities->CallLogPop(560);
6949  return true;
6950  }
6951  else
6952  {
6953  Utilities->CallLogPop(561);
6954  return false;
6955  }
6956 }
6957 
6958 // ---------------------------------------------------------------------------
6959 
6960 void TTrack::EnterLocationName(int Caller, AnsiString LocationName, bool AddingElements)
6961 {
6962 /*
6963  General:
6964  All platform, concourse, footcrossing & non-station named location elements are able to have a LocationName allocated, and track
6965  elements (including footcrossings) are able to have an ActiveTrackElementName allocated provided there is an adjacent platform or
6966  a NamedNonStationLocation.
6967  To set these names the user selects a single named location element (not a footcrossing), enters the name, and
6968  this is then allocated as a LocationName to all linked platform, concourse and footcrossing elements, and as an
6969  ActiveTrackElementName to all track elements adjacent to platforms (inc footcrossing tracks if (but only if) they have a
6970  platform at that location).
6971 
6972  Linked named location elements are those explained in TTrack::TTrack()
6973 
6974  Detail:
6975  Two containers are used for allocation of names - LNPendingList, and LNDone2MultiMap, each containing vector positions as
6976  integers and the Map using THVPairs as keys. An adjustment is made for the vector positions as follows:-
6977  inactive vector positions are stored as they are (since most NamedLocationElements are in the inactive vector), but active vector
6978  positions stored as (-1-True Position), so can hold both types in a single integer uniquely - not very elegant but it seems to
6979  work OK! e.g. vector position 0 would be stored as -1, position n would be stored as -1-n. To recover the true position
6980  from a stored value the same rule applies, i.e. -1-stored value, equivalent to -1-(-1-original) = -1+1+original = original.
6981 
6982  The List holds elements that have still to be processed, and the Map holds elements that have been processed. On entering
6983  this function a single element should be in the List (normally from the user's selection but can also be from
6984  SearchForAndUpdateLocationName), and the Map is cleared within the function.
6985  A 'while' loop is entered if the List isn't empty, and the front element in it examined. All linked named location elements
6986  (platforms, concourses and footcrossings) that aren't already in either the Map or the List are first added to the List using
6987  AdjElement, then the element itself has it's LocationName set, and any relevant track elements at the same H & V (i.e. adjacent
6988  to a platform) have their ActiveTrackElementName set using AddName. The element is then inserted into the Map and erased from the List.
6989  In this way the list builds up while there are linked elements to be added, but reduces to zero when all are added and processing
6990  moves them into the Map. At the end all linked elements are in the Map.
6991 
6992  Finally any other element that isn't in the Map, i.e. not linked to the current named location, that has the same name as a
6993  LocationName or ActiveTrackElementName, has it erased. This is to allow for deletion of named location elements that split an existing
6994  named location - only one of the sides (selected by whichever the program finds first - the user can't select it) retains the name.
6995 */
6996 
6997 // AnsiString TestString = "H,V,Tag,List Size,DoneMultiMap Size,CurrentElementAddress,MultiMapEntryAddress";//test
6998 // Display->FileDiagnostics(TestString);//test
6999 
7000  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EnterLocationName," + LocationName);
7001  AnsiString TestString1, TestString2; // test
7002 
7003  Track->LNDone2MultiMap.clear();
7004  if(LNPendingList.size() != 1)
7005  {
7006  throw Exception("LNPendingList size not 1 on entry");
7007  }
7008  while(!LNPendingList.empty())
7009  {
7011  int NewElement; // = 2000000000; //marker for unused //not needed after v1.1.4
7012  int H = CurrentElement->HLoc;
7013  int V = CurrentElement->VLoc;
7014  int Tag = CurrentElement->SpeedTag;
7015  if(Tag == 76) // top plat
7016  {
7017  // AdjElement checks if there is an element matching Tag at H & V that isn't already in LNDone2MultiMap or LNPendingList,
7018  // & returns true if so with the adjusted vector position in NewElement. It checks the appropriate vector
7019  // depending on the SpeedTag value (footcrossings in active vector, rest in inactive vector),
7020  for(int x = 0; x < 25; x++)
7021  {
7022  if(AdjElement(1, H + Tag76Array[x][0], V + Tag76Array[x][1], Tag76Array[x][2], NewElement))
7023  {
7024  LNPendingList.insert(LNPendingList.end(), NewElement);
7025  }
7026  }
7027  }
7028  else if(Tag == 77) // bot plat
7029  {
7030  for(int x = 0; x < 25; x++)
7031  {
7032  if(AdjElement(2, H + Tag77Array[x][0], V + Tag77Array[x][1], Tag77Array[x][2], NewElement))
7033  {
7034  LNPendingList.insert(LNPendingList.end(), NewElement);
7035  }
7036  }
7037  }
7038  else if(Tag == 78) // l plat
7039  {
7040  for(int x = 0; x < 25; x++)
7041  {
7042  if(AdjElement(3, H + Tag78Array[x][0], V + Tag78Array[x][1], Tag78Array[x][2], NewElement))
7043  {
7044  LNPendingList.insert(LNPendingList.end(), NewElement);
7045  }
7046  }
7047  }
7048  else if(Tag == 79) // r plat
7049  {
7050  for(int x = 0; x < 25; x++)
7051  {
7052  if(AdjElement(4, H + Tag79Array[x][0], V + Tag79Array[x][1], Tag79Array[x][2], NewElement))
7053  {
7054  LNPendingList.insert(LNPendingList.end(), NewElement);
7055  }
7056  }
7057  }
7058  else if(Tag == 96) // conc
7059  {
7060  for(int x = 0; x < 28; x++)
7061  {
7062  if(AdjElement(5, H + Tag96Array[x][0], V + Tag96Array[x][1], Tag96Array[x][2], NewElement))
7063  {
7064  LNPendingList.insert(LNPendingList.end(), NewElement);
7065  }
7066  }
7067  }
7068  else if(Tag == 129) // vert footbridge
7069  {
7070  for(int x = 0; x < 8; x++)
7071  {
7072  if(AdjElement(6, H + Tag129Array[x][0], V + Tag129Array[x][1], Tag129Array[x][2], NewElement))
7073  {
7074  LNPendingList.insert(LNPendingList.end(), NewElement);
7075  }
7076  }
7077  }
7078  else if(Tag == 130) // hor footbridge
7079  {
7080  for(int x = 0; x < 8; x++)
7081  {
7082  if(AdjElement(7, H + Tag130Array[x][0], V + Tag130Array[x][1], Tag130Array[x][2], NewElement))
7083  {
7084  LNPendingList.insert(LNPendingList.end(), NewElement);
7085  }
7086  }
7087  }
7088  else if(Tag == 131) // named location
7089  {
7090  for(int x = 0; x < 4; x++)
7091  {
7092  if(AdjElement(8, H + Tag131Array[x][0], V + Tag131Array[x][1], Tag131Array[x][2], NewElement))
7093  {
7094  LNPendingList.insert(LNPendingList.end(), NewElement);
7095  }
7096  }
7097  }
7098  else if(Tag == 145) // v u'pass
7099  {
7100  for(int x = 0; x < 8; x++)
7101  {
7102  if(AdjElement(9, H + Tag145Array[x][0], V + Tag145Array[x][1], Tag145Array[x][2], NewElement))
7103  {
7104  LNPendingList.insert(LNPendingList.end(), NewElement);
7105  }
7106  }
7107  }
7108  else if(Tag == 146) // h u'pass
7109  {
7110  for(int x = 0; x < 8; x++)
7111  {
7112  if(AdjElement(10, H + Tag146Array[x][0], V + Tag146Array[x][1], Tag146Array[x][2], NewElement))
7113  {
7114  LNPendingList.insert(LNPendingList.end(), NewElement);
7115  }
7116  }
7117  }
7118  // below new at v1.1.0 but condition changed at v1.1.4 as interfered with name changes for single element locations
7119 // if(NewElement != 2000000000) //adjacent element found & new element inserted, check if a (different) name already allocated and if so erase it from text vector
7120  if(AddingElements)
7121  {
7122  int HPos, VPos; // not used but needed for FindText function
7123  if(NewElement > -1)
7124  {
7125  AnsiString ExistingName = InactiveTrackElementAt(118, NewElement).LocationName;
7126  if((ExistingName != "") && (ExistingName != LocationName))
7127  {
7128  if(LocationNameMultiMap.find(ExistingName) == Track->LocationNameMultiMap.end())
7129  {} // name not in LocationNameMultiMap, so don't erase from TextVector
7130  else if(TextHandler->FindText(4, ExistingName, HPos, VPos)) // can't use 'EraseLocationNameText' as that function is in TInterface
7131  {
7132  if(TextHandler->TextErase(10, HPos, VPos))
7133  {;
7134  } // condition not used
7135  }
7136  }
7137  }
7138  }
7139 
7140  AddName(1, CurrentElement, LocationName); // add location name to current element, + timetable name to any
7141  // track at that loc
7142  THVPair HVPair(H, V);
7143  TLNDone2MultiMapEntry LNDone2MultiMapEntry;
7144  LNDone2MultiMapEntry.first = HVPair;
7145  LNDone2MultiMapEntry.second = LNPendingList.front();
7146  LNDone2MultiMap.insert(LNDone2MultiMapEntry);
7147  LNPendingList.erase(LNPendingList.begin());
7148  }
7149 
7150 // search all name multimap for same name where corresponding active elements don't appear in
7151 // LNDone2MultiMap & erase the name for all elements at that H & V in both active & inactive vectors
7152 
7153  TLocationNameMultiMapIterator SNIterator;
7154  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
7155  bool FoundFlag, ErasedFlag = false;
7156 
7157  if(SNRange.first != SNRange.second)
7158  {
7159  SNRange.first--; // now pointing to before the first
7160  SNRange.second--; // now pointing to the last
7161  for(SNIterator = SNRange.second; SNIterator != SNRange.first; SNIterator--)
7162  // Same elements are in Done map as in name map
7163  {
7164  if(!ElementInLNDone2MultiMap(1, SNIterator->second))
7165  {
7166  ErasedFlag = true;
7167  TTrackVectorIterator TVIt = GetTrackVectorIteratorFromNamePosition(2, SNIterator->second);
7168  TVIt->LocationName = "";
7169  TVIt->ActiveTrackElementName = ""; // in case it's a footcrossing
7170  // need to erase the timetable name in a track element at same H&V if present (i.e. if a platform)
7171  if((TVIt->TrackType == Platform) || (TVIt->TrackType == NamedNonStationLocation))
7172  {
7173  int Position = GetVectorPositionFromTrackMap(17, TVIt->HLoc, TVIt->VLoc, FoundFlag);
7174  if(FoundFlag)
7175  {
7176  TrackElementAt(20, Position).LocationName = "";
7177  TrackElementAt(21, Position).ActiveTrackElementName = "";
7178  }
7179  }
7180  // erase name in name map
7181 // ChangeLocationNameMultiMapEntry("", SNIterator); can't use this as interferes with the iterators
7182  }
7183  }
7184  }
7185  if(ErasedFlag)
7187  if(TrackFinished)
7189 // set here as well as in LinkTrack so don't have to link track just because a name added
7190 // if track not finished then will be set when track validated
7191  CheckLocationNameMultiMap(1); // test
7192  Utilities->CallLogPop(562);
7193 }
7194 
7195 // ---------------------------------------------------------------------------
7196 
7197 bool TTrack::AdjElement(int Caller, int HLoc, int VLoc, int SpeedTag, int &FoundElement)
7198 /*
7199  Looks for a FixedNamedLocationElement at H & V with SpeedTag, and if found and not already present in either the
7200  LNDone2MultiMap or the LNPendingList returns an int corresponding to the adjusted vector position.
7201 */
7202 {
7203  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AdjElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
7204  AnsiString(SpeedTag));
7205  if(!NamedLocationElementAt(2, HLoc, VLoc))
7206  {
7207  Utilities->CallLogPop(948);
7208  return false;
7209  }
7210  bool FoundFlag;
7211  int Position = -1;
7212  TIMPair IMPair;
7213 
7214  if((SpeedTag == 129) || (SpeedTag == 130) || (SpeedTag == 145) || (SpeedTag == 146)) // footcrossing - only in active vector
7215  {
7216  Position = GetVectorPositionFromTrackMap(18, HLoc, VLoc, FoundFlag);
7217  if(FoundFlag)
7218  {
7219  if(TrackElementAt(22, Position).SpeedTag == SpeedTag)
7220  {
7221  int MapPos = -1 - Position; // MapPos is the adjusted entry in the list & map
7222  if(!ElementInLNDone2MultiMap(2, MapPos) && !ElementInLNPendingList(1, MapPos))
7223  // don't allow duplicates in either list, or processing takes a lot longer
7224  {
7225  FoundElement = MapPos;
7226  Utilities->CallLogPop(563);
7227  return true;
7228  }
7229  }
7230  }
7231  }
7232  else
7233  {
7234  IMPair = GetVectorPositionsFromInactiveTrackMap(8, HLoc, VLoc, FoundFlag);
7235  if(FoundFlag)
7236  {
7237  if(InactiveTrackElementAt(12, IMPair.first).SpeedTag == SpeedTag)
7238  {
7239  if(!ElementInLNDone2MultiMap(3, IMPair.first) && !ElementInLNPendingList(2, IMPair.first))
7240  {
7241  FoundElement = IMPair.first;
7242  Utilities->CallLogPop(564);
7243  return true;
7244  }
7245  }
7246  else if(InactiveTrackElementAt(13, IMPair.second).SpeedTag == SpeedTag)
7247  {
7248  if(!ElementInLNDone2MultiMap(4, IMPair.second) && !ElementInLNPendingList(3, IMPair.second))
7249  {
7250  FoundElement = IMPair.second;
7251  Utilities->CallLogPop(565);
7252  return true;
7253  }
7254  }
7255  }
7256  }
7257  Utilities->CallLogPop(566);
7258  return false;
7259 }
7260 
7261 // ---------------------------------------------------------------------------
7262 
7263 void TTrack::AddName(int Caller, TTrackVectorIterator TrackElement, AnsiString Name)
7264 /*
7265  Add location name to TrackElement and ActiveTrackElementName to any elements in trackmap
7266  at same H & V if TrackElement is a Platform or named non-station location. Also update LocationNameMultiMap
7267  with the new name
7268 */
7269 {
7270  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AddName," + TrackElement->LogTrack(6) + "," + Name);
7271  AnsiString OldName = TrackElement->LocationName, ErrorString; // declare new AnsiStrings OldName (set to existing name) & ErrorString
7272 
7273  TrackElement->LocationName = Name; // covers all FixedNamedLocationElement whichever vector they are in
7274  int HLoc = TrackElement->HLoc;
7275  int VLoc = TrackElement->VLoc;
7276  bool FoundFlag;
7277 
7278  if((TrackElement->TrackType == Platform) || (TrackElement->TrackType == NamedNonStationLocation))
7279  // only have timetable names for adjacent platforms & named locations
7280  {
7281  int Position = GetVectorPositionFromTrackMap(19, HLoc, VLoc, FoundFlag);
7282  if(FoundFlag)
7283  {
7284  TrackElementAt(23, Position).ActiveTrackElementName = Name;
7285  }
7286  }
7287  TLocationNameMultiMapIterator SNIterator = FindNamedElementInLocationNameMultiMap(4, OldName, TrackElement, ErrorString);
7288 
7289  if(ErrorString != "")
7290  {
7291  throw Exception(ErrorString + " in AddName for OldName == " + OldName);
7292  }
7293  ChangeLocationNameMultiMapEntry(1, Name, SNIterator); // OK, can use it here as not in an iterator loop
7294  CheckLocationNameMultiMap(2); // test
7295  Utilities->CallLogPop(567);
7296 }
7297 
7298 // ---------------------------------------------------------------------------
7299 
7300 bool TTrack::ElementInLNDone2MultiMap(int Caller, int MapPos)
7301 /*
7302  Examines LNDone2MultiMap to see whether the MapPos value is present, and returns true if so.
7303 */
7304 {
7305  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ElementInLNDone2MultiMap," + AnsiString(MapPos));
7306  if(LNDone2MultiMap.empty())
7307  {
7308  Utilities->CallLogPop(568);
7309  return false;
7310  }
7311  TLNDone2MultiMapIterator LNDone2MultiMapIterator;
7312 
7313  for(LNDone2MultiMapIterator = LNDone2MultiMap.begin(); LNDone2MultiMapIterator != LNDone2MultiMap.end(); LNDone2MultiMapIterator++)
7314  {
7315  if(LNDone2MultiMapIterator->second == MapPos)
7316  {
7317  Utilities->CallLogPop(569);
7318  return true;
7319  }
7320  }
7321  Utilities->CallLogPop(570);
7322  return false;
7323 }
7324 
7325 // ---------------------------------------------------------------------------
7326 
7327 bool TTrack::ElementInLNPendingList(int Caller, int MapPos)
7328 /*
7329  Examines LNPendingList to see whether the MapPos value is present, and returns true if so.
7330 */
7331 {
7332  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ElementInLNPendingList," + AnsiString(MapPos));
7333  if(LNPendingList.empty())
7334  {
7335  Utilities->CallLogPop(571);
7336  return false;
7337  }
7338  TLNPendingListIterator LNPendingListIterator;
7339 
7340  for(LNPendingListIterator = LNPendingList.begin(); LNPendingListIterator != LNPendingList.end(); LNPendingListIterator++)
7341  {
7342  if(*LNPendingListIterator == MapPos)
7343  {
7344  Utilities->CallLogPop(572);
7345  return true;
7346  }
7347  }
7348  Utilities->CallLogPop(573);
7349  return false;
7350 }
7351 
7352 // ---------------------------------------------------------------------------
7353 
7354 bool TTrack::NamedLocationElementAt(int Caller, int HLoc, int VLoc)
7355 /*
7356  Examines element at H & V, and returns true if its FixedNamedLocationElement bool is true
7357 */
7358 {
7359  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NamedLocationElementAt," + AnsiString(HLoc) + "," + AnsiString(VLoc));
7360  THVPair HVPair(HLoc, VLoc);
7361  TTrackMapIterator TrackMapPtr = TrackMap.find(HVPair);
7362  TInactiveTrack2MultiMapIterator InactiveTrack2MultiMapIterator = InactiveTrack2MultiMap.find(HVPair);
7363 
7364  if(TrackMapPtr != TrackMap.end()) // =end() if not found
7365  {
7366  if(TrackElementAt(24, TrackMapPtr->second).FixedNamedLocationElement)
7367  {
7368  Utilities->CallLogPop(574);
7369  return true;
7370  }
7371  }
7372  if(InactiveTrack2MultiMapIterator != InactiveTrack2MultiMap.end())
7373  // may be 2 platforms at location but if so both FixedNamedLocationElement bools will be set, so only need to find one
7374  {
7375  if(InactiveTrackElementAt(14, InactiveTrack2MultiMapIterator->second).FixedNamedLocationElement)
7376  {
7377  Utilities->CallLogPop(575);
7378  return true;
7379  }
7380  }
7381  Utilities->CallLogPop(576);
7382  return false;
7383 }
7384 
7385 // ---------------------------------------------------------------------------
7386 
7387 bool TTrack::LocationNameAllocated(int Caller, AnsiString LocationName) // true if a non-empty LocationName found in LocationNameMultiMap
7388 {
7389  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LocationNameAllocated," + LocationName);
7390  if(Track->LocationNameMultiMap.find(LocationName) != Track->LocationNameMultiMap.end())
7391  {
7392  Utilities->CallLogPop(1953);
7393  return true;
7394  }
7395  Utilities->CallLogPop(1954);
7396  return false;
7397 }
7398 
7399 // ---------------------------------------------------------------------------
7400 
7401 bool TTrack::TimetabledLocationNameAllocated(int Caller, AnsiString LocationName)
7402 /*
7403  Examines ActiveTrackElementNameMap and returns true if the LocationName is found and isn't "" (used to use LocationNameMultiMap)
7404 */
7405 
7406 {
7407  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TimetabledLocationNameAllocated," + LocationName);
7408  if(LocationName == "")
7409  {
7410  Utilities->CallLogPop(577);
7411  return false;
7412  }
7413 // new for v0.2b
7414 // compile ActiveTrackElementNameMap if !ActiveTrackElementNameMapCompiledFlag (added as a precaution, should be compiled when reach here)
7416  {
7417  TActiveTrackElementNameMapEntry ActiveTrackElementNameMapEntry;
7418  ActiveTrackElementNameMap.clear();
7419  for(unsigned int x = 0; x < TrackVector.size(); x++)
7420  {
7421  if((TrackVector.at(x).ActiveTrackElementName != "") && (ContinuationNameMap.find(TrackVector.at(x).ActiveTrackElementName))
7422  == ContinuationNameMap.end())
7423  { // exclude any name that appears in a continuation, error message given in tt validation if try to include such a name in a tt
7424  ActiveTrackElementNameMapEntry.first = Track->TrackVector.at(x).ActiveTrackElementName;
7425  ActiveTrackElementNameMapEntry.second = 0; // this is a dummy value
7426  ActiveTrackElementNameMap.insert(ActiveTrackElementNameMapEntry);
7427  }
7428  }
7430  }
7431  Utilities->CallLogPop(578);
7432  return (ActiveTrackElementNameMap.find(LocationName) != ActiveTrackElementNameMap.end());
7433 // end of new section
7434 // return (LocationNameMultiMap.find(LocationName) != LocationNameMultiMap.end());
7435 }
7436 
7437 // ---------------------------------------------------------------------------
7438 
7439 void TTrack::EraseLocationAndActiveTrackElementNames(int Caller, AnsiString LocationName)
7440 /*
7441  Examines LocationNameMultiMap and if the LocationName is found all elements at that H & V (in both active and inactive vectors) have the
7442  name erased both as a LocationName and a ActiveTrackElementName. The LocationNameMultiMap is also rebuilt to correspond to the
7443  new names in the vectors.
7444 */
7445 {
7446  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EraseLocationAndActiveTrackElementNames," + LocationName);
7447  bool FoundFlag, ErasedFlag = false;
7448  TLocationNameMultiMapIterator SNIterator;
7449  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
7450 
7451  if(SNRange.first != SNRange.second)
7452  {
7453  ErasedFlag = true;
7454  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
7455  {
7456  TTrackVectorIterator TVIt = GetTrackVectorIteratorFromNamePosition(3, SNIterator->second);
7457  TVIt->LocationName = "";
7458  TVIt->ActiveTrackElementName = ""; // in case it's a footcrossing
7459  // need to erase the timetable name in a track element at same H&V if present (i.e. if a platform or namedlocation)
7460  if((TVIt->TrackType == Platform) || (TVIt->TrackType == NamedNonStationLocation))
7461  {
7462  int Position = GetVectorPositionFromTrackMap(20, TVIt->HLoc, TVIt->VLoc, FoundFlag);
7463  if(FoundFlag)
7464  {
7465  TrackElementAt(25, Position).LocationName = "";
7466  TrackElementAt(26, Position).ActiveTrackElementName = "";
7467  }
7468  }
7469  }
7470  }
7471  if(ErasedFlag)
7473  CheckLocationNameMultiMap(3); // test
7474  Utilities->CallLogPop(579);
7475 }
7476 
7477 // ---------------------------------------------------------------------------
7478 
7479 void TTrack::SearchForAndUpdateLocationName(int Caller, int HLoc, int VLoc, int SpeedTag)
7480 /*
7481  NB No longer used during EraseTrackElement, too long-winded - erase all name now if any part removed, user needs to re-enter
7482  Checks all locations that are adjacent to the one entered for linked named location elements, and if any LocationName is found
7483  in any of the linked elements that name is used for all elements that are now linked to it. The location entered doesn't
7484  need to be a FixedNamedLocationElement and there doesn't even need to be an element there. Used during EraseTrackElement (in which
7485  case the SpeedTag is that for the element that is erased) and PlotAndAddTrackElement, to bring the named location and timetable
7486  naming up to date with the deletion or insertion.
7487 */
7488 {
7489  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchForAndUpdateLocationName," + AnsiString(HLoc) + "," +
7490  AnsiString(VLoc) + "," + AnsiString(SpeedTag));
7491  LNPendingList.clear();
7492  AnsiString LocationName;
7493  int MapPos;
7494 
7495  if(SpeedTag == 76) // top plat
7496  {
7497  for(int x = 0; x < 25; x++)
7498  {
7499  if(AdjNamedElement(1, HLoc + Tag76Array[x][0], VLoc + Tag76Array[x][1], Tag76Array[x][2], LocationName, MapPos))
7500  {
7501  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
7502  EnterLocationName(3, LocationName, true);
7503  break;
7504  }
7505  }
7506  }
7507  else if(SpeedTag == 77) // bot plat
7508  {
7509  for(int x = 0; x < 25; x++)
7510  {
7511  if(AdjNamedElement(2, HLoc + Tag77Array[x][0], VLoc + Tag77Array[x][1], Tag77Array[x][2], LocationName, MapPos))
7512  {
7513  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
7514  EnterLocationName(4, LocationName, true);
7515  break;
7516  }
7517  }
7518  }
7519  else if(SpeedTag == 78) // l plat
7520  {
7521  for(int x = 0; x < 25; x++)
7522  {
7523  if(AdjNamedElement(3, HLoc + Tag78Array[x][0], VLoc + Tag78Array[x][1], Tag78Array[x][2], LocationName, MapPos))
7524  {
7525  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
7526  EnterLocationName(5, LocationName, true);
7527  break;
7528  }
7529  }
7530  }
7531  else if(SpeedTag == 79) // r plat
7532  {
7533  for(int x = 0; x < 25; x++)
7534  {
7535  if(AdjNamedElement(4, HLoc + Tag79Array[x][0], VLoc + Tag79Array[x][1], Tag79Array[x][2], LocationName, MapPos))
7536  {
7537  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
7538  EnterLocationName(6, LocationName, true);
7539  break;
7540  }
7541  }
7542  }
7543  else if(SpeedTag == 96) // conc
7544  {
7545  for(int x = 0; x < 28; x++)
7546  {
7547  if(AdjNamedElement(5, HLoc + Tag96Array[x][0], VLoc + Tag96Array[x][1], Tag96Array[x][2], LocationName, MapPos))
7548  {
7549  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
7550  EnterLocationName(7, LocationName, true);
7551  break;
7552  }
7553  }
7554  }
7555  else if(SpeedTag == 129) // vert footbridge
7556  {
7557  for(int x = 0; x < 8; x++)
7558  {
7559  if(AdjNamedElement(6, HLoc + Tag129Array[x][0], VLoc + Tag129Array[x][1], Tag129Array[x][2], LocationName, MapPos))
7560  {
7561  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
7562  EnterLocationName(8, LocationName, true);
7563  break;
7564  }
7565  }
7566  }
7567  else if(SpeedTag == 130) // hor footbridge
7568  {
7569  for(int x = 0; x < 8; x++)
7570  {
7571  if(AdjNamedElement(7, HLoc + Tag130Array[x][0], VLoc + Tag130Array[x][1], Tag130Array[x][2], LocationName, MapPos))
7572  {
7573  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
7574  EnterLocationName(9, LocationName, true);
7575  break;
7576  }
7577  }
7578  }
7579  else if(SpeedTag == 145) // vert u'pass
7580  {
7581  for(int x = 0; x < 8; x++)
7582  {
7583  if(AdjNamedElement(9, HLoc + Tag145Array[x][0], VLoc + Tag145Array[x][1], Tag145Array[x][2], LocationName, MapPos))
7584  {
7585  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
7586  EnterLocationName(11, LocationName, true);
7587  break;
7588  }
7589  }
7590  }
7591  else if(SpeedTag == 146) // hor u'pass
7592  {
7593  for(int x = 0; x < 8; x++)
7594  {
7595  if(AdjNamedElement(10, HLoc + Tag146Array[x][0], VLoc + Tag146Array[x][1], Tag146Array[x][2], LocationName, MapPos))
7596  {
7597  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
7598  EnterLocationName(12, LocationName, true);
7599  break;
7600  }
7601  }
7602  }
7603  else if(SpeedTag == 131) // named location
7604  {
7605  for(int x = 0; x < 4; x++)
7606  {
7607  if(AdjNamedElement(8, HLoc + Tag131Array[x][0], VLoc + Tag131Array[x][1], Tag131Array[x][2], LocationName, MapPos))
7608  {
7609  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
7610  EnterLocationName(10, LocationName, true);
7611  break;
7612  }
7613  }
7614  }
7615 // AddName(HLoc, VLoc, LocationName);//don't need this now, EnterLocationName takes care of it
7616  Utilities->CallLogPop(580);
7617 }
7618 
7619 // ---------------------------------------------------------------------------
7620 
7621 bool TTrack::AdjNamedElement(int Caller, int HLoc, int VLoc, int SpeedTag, AnsiString &LocationName, int &FoundElement)
7622 /*
7623  Used in SearchForAndUpdateLocationName to check for elements in TrackMap & InactiveTrackMap that match H, V & Tag, & returns
7624  true if a LocationName is found, and also returns the name and the adjusted vector position.
7625 */
7626 {
7627  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AdjNamedElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
7628  AnsiString(SpeedTag));
7629  bool FoundFlag;
7630  TIMPair IMPair;
7631  TTrackVectorIterator TempElement;
7632  int Position;
7633 
7634  IMPair = GetVectorPositionsFromInactiveTrackMap(9, HLoc, VLoc, FoundFlag);
7635  if(FoundFlag)
7636  {
7637  if(InactiveTrackElementAt(15, IMPair.first).SpeedTag == SpeedTag)
7638  {
7639  TempElement = InactiveTrackVector.begin() + IMPair.first;
7640  if(TempElement->LocationName != "")
7641  {
7642  LocationName = TempElement->LocationName;
7643  FoundElement = IMPair.first;
7644  Utilities->CallLogPop(581);
7645  return true;
7646  }
7647  }
7648  else if(InactiveTrackElementAt(16, IMPair.second).SpeedTag == SpeedTag)
7649  {
7650  TempElement = InactiveTrackVector.begin() + IMPair.second;
7651  if(TempElement->LocationName != "")
7652  {
7653  LocationName = TempElement->LocationName;
7654  FoundElement = IMPair.second;
7655  Utilities->CallLogPop(582);
7656  return true;
7657  }
7658  }
7659  }
7660 
7661  Position = GetVectorPositionFromTrackMap(21, HLoc, VLoc, FoundFlag);
7662  if(FoundFlag)
7663  {
7664  if(TrackElementAt(27, Position).SpeedTag == SpeedTag)
7665  {
7666  TempElement = TrackVector.begin() + Position;
7667  if(TempElement->LocationName != "")
7668  {
7669  LocationName = TempElement->LocationName;
7670  FoundElement = -1 - Position;
7671  Utilities->CallLogPop(583);
7672  return true;
7673  }
7674  }
7675  }
7676  Utilities->CallLogPop(584);
7677  return false;
7678 }
7679 
7680 // ---------------------------------------------------------------------------
7681 
7682 void TTrack::CheckLocationNameMultiMap(int Caller) // test function
7683 {
7684 // check quantity in map & vectors match
7685  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckLocationNameMultiMap,");
7686  unsigned int Count = 0;
7687 
7688  if(SkipLocationNameMultiMapCheck) // renamed in v2.4.0 to skip check when pasting because fails as map elements not fully aligned until all pasted
7689  {
7690  Utilities->CallLogPop(2059);
7691  return;
7692  }
7693 
7694  AnsiString SName, TName, ErrorString;
7695 
7696  for(unsigned int x = 0; x < TrackVector.size(); x++)
7697  {
7698  if(TrackVector.at(x).FixedNamedLocationElement)
7699  {
7700  if(TrackVector.at(x).TrackType != FootCrossing)
7701  {
7702  throw Exception("Track element has FixedNamedLocationElement set but is not a footbridge/underpass in CheckLocationNameMultiMap, caller = " +
7703  AnsiString(Caller));
7704  }
7705  Count++;
7706  }
7707  }
7708  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
7709  {
7710  if(InactiveTrackVector.at(x).FixedNamedLocationElement)
7711  {
7712  if((InactiveTrackVector.at(x).TrackType != Platform) && (InactiveTrackVector.at(x).TrackType != NamedNonStationLocation) &&
7713  (InactiveTrackVector.at(x).TrackType != Concourse))
7714  {
7715  throw Exception
7716  ("Inactive track element has FixedNamedLocationElement set but is not a platform, concourse or named location in CheckLocationNameMultiMap, caller = " +
7717  AnsiString(Caller));
7718  }
7719  Count++;
7720  }
7721  }
7722  if(LocationNameMultiMap.size() != Count)
7723  {
7724  throw Exception("LocationNameMultiMap size = " + AnsiString(LocationNameMultiMap.size()) + " & Count = " + AnsiString(Count) +
7725  " in CheckLocationNameMultiMap, caller = " + AnsiString(Caller));
7726  }
7727 
7728 // check all entries in both vectors match entries in name multimap
7730 
7731  for(unsigned int x = 0; x < TrackVector.size(); x++)
7732  {
7733  if(TrackVector.at(x).FixedNamedLocationElement)
7734  {
7735  SName = TrackVector.at(x).LocationName;
7736  SNIt = FindNamedElementInLocationNameMultiMap(5, SName, TrackVector.begin() + x, ErrorString);
7737  if(ErrorString != "")
7738  {
7739  throw Exception(ErrorString + " in CheckLocationNameMultiMap for TrackVector check, caller = " + AnsiString(Caller));
7740  }
7741  if(SNIt->second != -1 - (int)x)
7742  {
7743  throw Exception("Elements different in name map & TrackVector in CheckLocationNameMultiMap for TrackVector check, caller = " +
7744  AnsiString(Caller));
7745  }
7746  }
7747  // check corresponding platform for all Timetable entries that aren't empty
7748  TName = TrackVector.at(x).ActiveTrackElementName;
7749  TIMPair IMPair;
7750  bool FoundFlag = false;
7751  if(TName != "")
7752  {
7753  IMPair = GetVectorPositionsFromInactiveTrackMap(10, TrackVector.at(x).HLoc, TrackVector.at(x).VLoc, FoundFlag);
7754  if(FoundFlag)
7755  {
7756  if((InactiveTrackElementAt(17, IMPair.first).TrackType != Platform) && (InactiveTrackElementAt(18, IMPair.second).TrackType != Platform) &&
7758  {
7759  throw Exception("Track element with ActiveTrackElementName but no plat/named loc at H " + AnsiString(TrackVector.at(x).HLoc) + " & V " +
7760  AnsiString(TrackVector.at(x).VLoc) + " in CheckLocationNameMultiMap, caller = " + AnsiString(Caller));
7761  }
7762  if((InactiveTrackElementAt(20, IMPair.first).LocationName != TName) && (InactiveTrackElementAt(21, IMPair.second).LocationName != TName))
7763  {
7764  throw Exception("Track element with ActiveTrackElementName " + TName + " but plat/named loc at H " + AnsiString(TrackVector.at(x).HLoc) +
7765  " & V " + AnsiString(TrackVector.at(x).VLoc) + " has different LocationName in CheckLocationNameMultiMap, caller = " +
7766  AnsiString(Caller));
7767  }
7768  }
7769  else
7770  {
7771  throw Exception("Track element with ActiveTrackElementName but no inactive element at H " + AnsiString(TrackVector.at(x).HLoc) + " & V " +
7772  AnsiString(TrackVector.at(x).VLoc) + " in CheckLocationNameMultiMap, caller = " + AnsiString(Caller));
7773  }
7774  }
7775  }
7776  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
7777  {
7778  if(InactiveTrackVector.at(x).FixedNamedLocationElement)
7779  {
7780  SName = InactiveTrackVector.at(x).LocationName;
7781  SNIt = FindNamedElementInLocationNameMultiMap(6, SName, InactiveTrackVector.begin() + x, ErrorString);
7782  if(ErrorString != "")
7783  {
7784  throw Exception(ErrorString + " in CheckLocationNameMultiMap for InactiveTrackVector check, caller = " + AnsiString(Caller));
7785  }
7786  if(SNIt->second != (int)x)
7787  {
7788  throw Exception("Elements different in name map & TrackVector in CheckLocationNameMultiMap for TrackVector check, caller = " +
7789  AnsiString(Caller));
7790  }
7791  }
7792  }
7793  Utilities->CallLogPop(585);
7794 }
7795 
7796 // ---------------------------------------------------------------------------
7797 
7799  AnsiString &ErrorString)
7800 {
7801 /*
7802  Searches the name map to check if the element pointed to by the TTrackVectorIterator has the name
7803  LocationName. If it finds it the pointer TLocationNameMultiMapIterator is returned. If it fails ErrorString
7804  is set to an appropriate text to allow the calling function to report the error. Otherwise it is set to "".
7805 */
7806  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindNamedElementInLocationNameMultiMap," + LocationName + "," +
7807  AnsiString(TrackElement->HLoc) + "," + AnsiString(TrackElement->VLoc) + "," + AnsiString(TrackElement->SpeedTag));
7808  ErrorString = "";
7809  bool FoundFlag = false;
7810  TLocationNameMultiMapIterator SNIterator;
7811  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
7812 
7813  if(SNRange.first == SNRange.second)
7814  {
7815  ErrorString = "Error, Name " + LocationName + " not found in map";
7816  Utilities->CallLogPop(586);
7817  return SNRange.first;
7818  }
7819  else
7820  {
7821  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
7822  {
7823  if(SNIterator->second < 0)
7824  {
7825  int TVPos = -1 - SNIterator->second;
7826  TTrackVectorIterator TVIt = TrackVector.begin() + TVPos;
7827  if(TVIt == TrackElement)
7828  {
7829  FoundFlag = true;
7830  Utilities->CallLogPop(587);
7831  return SNIterator;
7832  }
7833  }
7834  else
7835  {
7836  int ITVPos = SNIterator->second;
7837  TTrackVectorIterator ITVIt = InactiveTrackVector.begin() + ITVPos;
7838  if(ITVIt == TrackElement)
7839  {
7840  FoundFlag = true;
7841  Utilities->CallLogPop(588);
7842  return SNIterator;
7843  }
7844  }
7845  }
7846  }
7847  if(!FoundFlag)
7848  ErrorString = "Error, Name " + LocationName + " found but not at required element";
7849  Utilities->CallLogPop(589);
7850  return SNIterator;
7851 }
7852 
7853 // ---------------------------------------------------------------------------
7854 
7855 void TTrack::ChangeLocationNameMultiMapEntry(int Caller, AnsiString NewName, TLocationNameMultiMapIterator SNIterator)
7856 {
7857 /*
7858  Changes the LocationName in the name multimap to NewName at the location pointed to by the TLocationNameMultiMapIterator
7859  from whatever it was before. Accepts null entries so that a formerly named element can have the name changed to "".
7860 */
7861  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ChangeLocationNameMultiMapEntry," + NewName);
7862  TLocationNameMultiMapEntry LocationNameEntry;
7863 
7864  LocationNameEntry.first = NewName;
7865  LocationNameEntry.second = SNIterator->second;
7866  LocationNameMultiMap.erase(SNIterator);
7867  LocationNameMultiMap.insert(LocationNameEntry);
7868  Utilities->CallLogPop(590);
7869 }
7870 
7871 // ---------------------------------------------------------------------------
7872 
7874 {
7875 // Takes an adjusted vector position value and returns a pointer to the relevant element. Can be in either vector.
7876  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackVectorIteratorFromNamePosition," + AnsiString(Position));
7877  if(Position < 0) // footcrossing
7878  {
7879  int TruePos = -1 - Position;
7880  // new check at v0.2b
7881  if(TrackElementAt(817, TruePos).TrackType != FootCrossing)
7882  {
7883  throw Exception("Footbridge/underpass error in GetTrackVectorIteratorFromNamePosition, caller = " + AnsiString(Caller));
7884  }
7885  Utilities->CallLogPop(591);
7886  return (TrackVector.begin() + TruePos);
7887  }
7888  else
7889  {
7890  // new check at v0.2b
7891  if(!(InactiveTrackElementAt(99, Position).FixedNamedLocationElement))
7892  {
7893  throw Exception("Inactive element error in GetTrackVectorIteratorFromNamePosition, caller = " + AnsiString(Caller));
7894  }
7895  Utilities->CallLogPop(592);
7896  return (InactiveTrackVector.begin() + Position);
7897  }
7898 }
7899 
7900 // ---------------------------------------------------------------------------
7901 
7902 void TTrack::DecrementValuesInInactiveTrackAndNameMaps(int Caller, unsigned int VecPos)
7903 {
7904 /*
7905  After an element has been erased from the inactive track vector, all the later elements are moved down one. This function
7906  decrements the position values for all values above that of the erased element in both InactiveTrack2MultiMap and
7907  LocationNameMultiMap.
7908 */
7909  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementValuesInInactiveTrackAndNameMaps," + AnsiString(VecPos));
7910  TInactiveTrack2MultiMapIterator InactiveTrack2MultiMapIterator;
7911  TLocationNameMultiMapIterator LocationNameMultiMapIterator;
7912 
7913  if(!InactiveTrack2MultiMap.empty())
7914  {
7915  for(InactiveTrack2MultiMapIterator = InactiveTrack2MultiMap.begin(); InactiveTrack2MultiMapIterator != InactiveTrack2MultiMap.end();
7916  InactiveTrack2MultiMapIterator++)
7917  {
7918  if(InactiveTrack2MultiMapIterator->second > VecPos)
7919  InactiveTrack2MultiMapIterator->second--;
7920  // can't be == VecPos as that position erased
7921  }
7922  }
7923  if(!LocationNameMultiMap.empty())
7924  {
7925  for(LocationNameMultiMapIterator = LocationNameMultiMap.begin(); LocationNameMultiMapIterator != LocationNameMultiMap.end();
7926  LocationNameMultiMapIterator++)
7927  {
7928  if(LocationNameMultiMapIterator->second < 0)
7929  continue; // deal with TrackVectors separately
7930  if(LocationNameMultiMapIterator->second > (int)VecPos)
7931  LocationNameMultiMapIterator->second--;
7932  }
7933  }
7934  Utilities->CallLogPop(593);
7935 }
7936 
7937 // ---------------------------------------------------------------------------
7938 
7939 void TTrack::DecrementValuesInGapsAndTrackAndNameMaps(int Caller, unsigned int VecPos)
7940 {
7941 /*
7942  After an element has been erased from the track vector, all the later elements are moved down one. This function
7943  decrements the position values for all values above that of the erased element in the gap elements, TrackMap and
7944  LocationNameMultiMap.
7945 */
7946  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementValuesInGapsAndTrackAndNameMaps," + AnsiString(VecPos));
7947  TTrackMapIterator TrackMapIterator;
7948  TLocationNameMultiMapIterator LocationNameMultiMapIterator;
7949 
7950  if(!TrackMap.empty())
7951  {
7952  for(TrackMapIterator = TrackMap.begin(); TrackMapIterator != TrackMap.end(); TrackMapIterator++)
7953  {
7954  if(TrackMapIterator->second > VecPos)
7955  TrackMapIterator->second--;
7956  // can't be == VecPos as that position erased
7957  }
7958  }
7959  if(!LocationNameMultiMap.empty())
7960  {
7961  for(LocationNameMultiMapIterator = LocationNameMultiMap.begin(); LocationNameMultiMapIterator != LocationNameMultiMap.end();
7962  LocationNameMultiMapIterator++)
7963  {
7964  if(LocationNameMultiMapIterator->second >= 0)
7965  continue; // deal with InactiveTrackVectors separately
7966  // (-1-VecPos) VP 0 1 2 3 4 5 6 7
7967  // Val -1 -2 -3 -4 -5 -6 -7 -8
7968  if(LocationNameMultiMapIterator->second < -(int)(VecPos + 1))
7969  LocationNameMultiMapIterator->second++;
7970  }
7971  }
7972  for(unsigned int x = 0; x < TrackVector.size(); x++)
7973  {
7974  TTrackElement &TkEl = TrackVector.at(x); // no need to check so use this to speed up
7975  if(TkEl.TrackType == GapJump)
7976  {
7977  // position 0 is the gap
7978  if(TkEl.Conn[0] == int(VecPos))
7979  {
7980  TkEl.Conn[0] = -1; // connected to a deleted gap
7981  continue;
7982  }
7983  if(TkEl.Conn[0] > int(VecPos))
7984  TkEl.Conn[0]--;
7985  if(TkEl.Conn[0] > -1) // don't use 'else' here, need to check the value whether changed or not
7986  {
7987  if(TrackElementAt(709, TkEl.Conn[0]).TrackType != GapJump)
7988  TkEl.Conn[0] = -1;
7989  }
7990  }
7991  }
7992  Utilities->CallLogPop(1433);
7993 }
7994 
7995 // ---------------------------------------------------------------------------
7996 
7998 /*
7999  Clears the existing LocationNameMultiMap and rebuilds it from TrackVector and InactiveTrackVector. Called after the
8000  track is linked as many of the vector positions are likely to change - called from RepositionAndMapTrack();
8001  after names are changed in EraseLocationAndActiveTrackElementNames; and after the name changes in EnterLocationName.
8002 */
8003 {
8004  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RebuildLocationNameMultiMap");
8005  LocationNameMultiMap.clear();
8006  TLocationNameMultiMapEntry LocationNameEntry;
8007  TTrackElement TrackElement;
8008 
8009  for(unsigned int TVPos = 0; TVPos < TrackVector.size(); TVPos++)
8010  {
8011  TrackElement = TrackVector.at(TVPos);
8012  if(TrackElement.FixedNamedLocationElement)
8013  {
8014  LocationNameEntry.first = TrackElement.LocationName;
8015  LocationNameEntry.second = -1 - TVPos; // adjusted for footcrossings
8016  LocationNameMultiMap.insert(LocationNameEntry);
8017  }
8018  }
8019 
8020  for(unsigned int ITVPos = 0; ITVPos < InactiveTrackVector.size(); ITVPos++)
8021  {
8022  TrackElement = InactiveTrackVector.at(ITVPos);
8023  if(TrackElement.FixedNamedLocationElement)
8024  {
8025  LocationNameEntry.first = TrackElement.LocationName;
8026  LocationNameEntry.second = ITVPos;
8027  LocationNameMultiMap.insert(LocationNameEntry);
8028  }
8029  }
8030  Utilities->CallLogPop(594);
8031 }
8032 
8033 // ---------------------------------------------------------------------------
8034 
8036  // Return true if there is a named location present in the railway
8037  // ignores lone footcrossings, can't name these on their own & track won't link if there are any
8038 {
8039  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NonFootCrossingNamedLocationExists");
8040  TTrackVectorIterator ITVI;
8041 
8042  if(InactiveTrackVector.empty())
8043  {
8044  Utilities->CallLogPop(1343);
8045  return false;
8046  }
8047  for(ITVI = InactiveTrackVector.begin(); ITVI != InactiveTrackVector.end(); ITVI++)
8048  {
8049  if((ITVI->TrackType == Platform) || (ITVI->TrackType == NamedNonStationLocation) || (ITVI->TrackType == Concourse))
8050  {
8051  Utilities->CallLogPop(1404);
8052  return true;
8053  }
8054  }
8055  Utilities->CallLogPop(1344);
8056  return false;
8057 }
8058 
8059 // ---------------------------------------------------------------------------
8060 
8062 /*
8063  Work through all elements in TrackVector setting all lengths & speed limits to default values - including both tracks for 2-track elements
8064 */
8065 {
8066  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetAllDefaultLengthsAndSpeedLimits");
8067 // ResetDistanceElements(6);
8068  for(unsigned int x = 0; x < TrackVector.size(); x++)
8069  {
8070  TTrackElement &TE = TrackElementAt(718, x);
8073  if((TE.TrackType == Points) || (TE.TrackType == Crossover) || (TE.TrackType == Bridge))
8074  {
8077  }
8078  }
8079 /* old function
8080  if((TrackVector.at(x).TrackType == Points) || (TrackVector.at(x).TrackType == Crossover) || (TrackVector.at(x).TrackType == Bridge))
8081  {
8082  SetOneDefaultTrackLength(2, TrackVector.at(x), 0);
8083  SetOneDefaultTrackLength(3, TrackVector.at(x), 2);
8084  }
8085  else
8086  {
8087  SetOneDefaultTrackLength(4, TrackVector.at(x), 0);
8088  }
8089  }
8090 */
8091  Utilities->CallLogPop(617);
8092 }
8093 
8094 // ---------------------------------------------------------------------------
8095 
8096 void TTrack::LengthMarker(int Caller, TDisplay *Disp)
8097  // Examine all elements in the TrackVector and if have a valid length mark the relevant track using MarkOneLength.
8098 {
8099  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LengthMarker");
8100  for(unsigned int x = 0; x < TrackVector.size(); x++)
8101  {
8102  TTrackElement TempElement = TrackVector.at(x);
8103  if(TempElement.Length01 > -1)
8104  MarkOneLength(1, TempElement, true, Disp); // need Length01 test in case there are erase elements (but shouldn't be after LinkTrack)
8105  if(TempElement.Length23 > -1)
8106  MarkOneLength(2, TempElement, false, Disp);
8107  }
8108  Disp->Update();
8109  Utilities->CallLogPop(618);
8110 }
8111 
8112 // ---------------------------------------------------------------------------
8113 
8114 void TTrack::MarkOneLength(int Caller, TTrackElement TrackElement, bool FirstTrack, TDisplay *Disp)
8115 /*
8116  Rule: Only marked if different in any way from the default values - length 100m and speed limit 200km/h
8117  First check using IsElementTrackDefaultLength whether the relevant track is already set to the default values, and if so
8118  return as nothing further to do. Otherwise pick up the appropriate bitmap (using the AutoSigRouteGraphicsPtr bitmaps)
8119  using the same technique as in TPrefDirElement::EntryExitNumber() & *TPrefDirElement::GetPrefDirGraphicPtr(), for the relevant
8120  track as indicated by FirstTrack (true for track01 & false for track23).
8121 */
8122 {
8123  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",MarkOneLength," + TrackElement.LogTrack(8) + "," +
8124  AnsiString((short)FirstTrack));
8125  bool LengthDifferent = false, SpeedDifferent = false;
8126 
8127  if(IsElementDefaultLength(1, TrackElement, FirstTrack, LengthDifferent, SpeedDifferent))
8128  {
8129  Utilities->CallLogPop(619);
8130  return;
8131  }
8132 
8133  int EXArray[16][2] =
8134  {{4, 6}, {2, 8}, // horizontal & vertical
8135  {2, 4}, {6, 2}, {8, 6}, {4, 8}, // sharp curves
8136  {1, 6}, {3, 8}, {9, 4}, {7, 2}, {1, 8}, {3, 4}, {9, 2}, {7, 6}, // loose curves
8137  {1, 9}, {3, 7}}; // forward & reverse diagonals
8138 
8139  int Index = -1, BrNum = -1, GrNum = -1, InLink, OutLink;
8140  Graphics::TBitmap *Bitmap;
8141 
8142  if(FirstTrack)
8143  {
8144  InLink = TrackElement.Link[0];
8145  OutLink = TrackElement.Link[1];
8146  }
8147  else
8148  {
8149  InLink = TrackElement.Link[2];
8150  OutLink = TrackElement.Link[3];
8151  }
8152 
8153  for(int x = 0; x < 16; x++)
8154  {
8155  if((InLink == EXArray[x][0] && OutLink == EXArray[x][1]) || (InLink == EXArray[x][1] && OutLink == EXArray[x][0]))
8156  Index = x;
8157  }
8158  if(Index == -1)
8159  {
8160  throw Exception("Error, failed to find Index in TTrack::MarkOneLength");
8161  }
8162 
8163 /* The order for bridge entries & exits is as below. Note that there are 3 of each type,
8164  the graphic for each of which is different because of the shape of the overbridge. The basic
8165  entry/exit value is computed above, and this used to select only from elements with that entry/exit
8166  value that is an underbridge, i.e overbridges ignored as the normal graphic is OK for them.
8167  int BrEXArray[24][2] = {
8168  {4,6},{2,8},{1,9},{3,7},
8169  {1,9},{3,7},{1,9},{3,7},
8170  {2,8},{4,6},{2,8},{4,6}
8171 */
8172  if(!FirstTrack && (TrackElement.TrackType == Bridge))
8173  {
8174  if(Index == 1)
8175  {
8176  if(TrackElement.SpeedTag == 49)
8177  BrNum = 1 + 16;
8178  else if(TrackElement.SpeedTag == 54)
8179  BrNum = 8 + 16;
8180  else if(TrackElement.SpeedTag == 55)
8181  BrNum = 10 + 16;
8182  }
8183  else if(Index == 0)
8184  {
8185  if(TrackElement.SpeedTag == 48)
8186  BrNum = 0 + 16;
8187  else if(TrackElement.SpeedTag == 58)
8188  BrNum = 11 + 16;
8189  else if(TrackElement.SpeedTag == 59)
8190  BrNum = 9 + 16;
8191  }
8192  else if(Index == 14)
8193  {
8194  if(TrackElement.SpeedTag == 50)
8195  BrNum = 2 + 16;
8196  else if(TrackElement.SpeedTag == 52)
8197  BrNum = 4 + 16;
8198  else if(TrackElement.SpeedTag == 57)
8199  BrNum = 6 + 16;
8200  }
8201  else if(Index == 15)
8202  {
8203  if(TrackElement.SpeedTag == 51)
8204  BrNum = 3 + 16;
8205  else if(TrackElement.SpeedTag == 53)
8206  BrNum = 7 + 16;
8207  else if(TrackElement.SpeedTag == 56)
8208  BrNum = 5 + 16;
8209  }
8210  }
8211 
8212  if(!FirstTrack && (TrackElement.TrackType == Bridge))
8213  GrNum = BrNum;
8214  else
8215  GrNum = Index;
8216 
8217  if(LengthDifferent && SpeedDifferent) // blue - use autosig graphics
8218  {
8219  if(GrNum > 15) // underbridge
8220  {
8221  Bitmap = RailGraphics->BridgeRouteAutoSigsGraphicsPtr[GrNum - 16];
8222  }
8223  else
8224  Bitmap = RailGraphics->LinkRouteAutoSigsGraphicsPtr[GrNum];
8225 
8226  if(TrackElement.SpeedTag == 64)
8227  Bitmap = RailGraphics->LinkRouteAutoSigsGraphicsPtr[16]; // intercept diagonal buffers to show the buffer
8228  if(TrackElement.SpeedTag == 65)
8230  if(TrackElement.SpeedTag == 66)
8232  if(TrackElement.SpeedTag == 67)
8234 
8235  if(TrackElement.SpeedTag == 80)
8236  Bitmap = RailGraphics->LinkRouteAutoSigsGraphicsPtr[20]; // intercept continuations to show the dots
8237  if(TrackElement.SpeedTag == 81)
8239  if(TrackElement.SpeedTag == 82)
8241  if(TrackElement.SpeedTag == 83)
8243  if(TrackElement.SpeedTag == 84)
8245  if(TrackElement.SpeedTag == 85)
8247  if(TrackElement.SpeedTag == 86)
8249  if(TrackElement.SpeedTag == 87)
8251 
8252  if(TrackElement.SpeedTag == 129)
8253  Bitmap = RailGraphics->LinkRouteAutoSigsGraphicsPtr[28]; // intercept under footbridges
8254  if(TrackElement.SpeedTag == 130)
8256  }
8257 
8258  else if(LengthDifferent && !SpeedDifferent) // green - use pref sig graphics
8259  {
8260  if(GrNum > 15) // underbridge
8261  {
8262  Bitmap = RailGraphics->BridgeSigRouteGraphicsPtr[GrNum - 16];
8263  }
8264  else
8265  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[GrNum];
8266 
8267  if(TrackElement.SpeedTag == 64)
8268  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[16]; // intercept diagonal buffers to show the buffer
8269  if(TrackElement.SpeedTag == 65)
8270  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[17];
8271  if(TrackElement.SpeedTag == 66)
8272  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[18];
8273  if(TrackElement.SpeedTag == 67)
8274  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[19];
8275 
8276  if(TrackElement.SpeedTag == 80)
8277  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[20]; // intercept continuations to show the dots
8278  if(TrackElement.SpeedTag == 81)
8279  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[21];
8280  if(TrackElement.SpeedTag == 82)
8281  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[22];
8282  if(TrackElement.SpeedTag == 83)
8283  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[23];
8284  if(TrackElement.SpeedTag == 84)
8285  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[24];
8286  if(TrackElement.SpeedTag == 85)
8287  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[25];
8288  if(TrackElement.SpeedTag == 86)
8289  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[26];
8290  if(TrackElement.SpeedTag == 87)
8291  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[27];
8292 
8293  if(TrackElement.SpeedTag == 129)
8294  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[28]; // intercept under footbridges
8295  if(TrackElement.SpeedTag == 130)
8296  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[29];
8297  }
8298 
8299  else // SpeedDifferent only: red - use non sig graphics
8300  {
8301  if(GrNum > 15) // underbridge
8302  {
8303  Bitmap = RailGraphics->BridgeNonSigRouteGraphicsPtr[GrNum - 16];
8304  }
8305  else
8306  Bitmap = RailGraphics->LinkNonSigRouteGraphicsPtr[GrNum];
8307 
8308  if(TrackElement.SpeedTag == 64)
8309  Bitmap = RailGraphics->LinkNonSigRouteGraphicsPtr[16]; // intercept diagonal buffers to show the buffer
8310  if(TrackElement.SpeedTag == 65)
8312  if(TrackElement.SpeedTag == 66)
8314  if(TrackElement.SpeedTag == 67)
8316 
8317  if(TrackElement.SpeedTag == 80)
8318  Bitmap = RailGraphics->LinkNonSigRouteGraphicsPtr[20]; // intercept continuations to show the dots
8319  if(TrackElement.SpeedTag == 81)
8321  if(TrackElement.SpeedTag == 82)
8323  if(TrackElement.SpeedTag == 83)
8325  if(TrackElement.SpeedTag == 84)
8327  if(TrackElement.SpeedTag == 85)
8329  if(TrackElement.SpeedTag == 86)
8331  if(TrackElement.SpeedTag == 87)
8333 
8334  if(TrackElement.SpeedTag == 129)
8335  Bitmap = RailGraphics->LinkNonSigRouteGraphicsPtr[28]; // intercept under footbridges
8336  if(TrackElement.SpeedTag == 130)
8338  }
8339 
8340  Disp->PlotOutput(67, TrackElement.HLoc * 16, TrackElement.VLoc * 16, Bitmap);
8341  Utilities->CallLogPop(620);
8342 }
8343 
8344 // ---------------------------------------------------------------------------
8345 
8346 bool TTrack::IsElementDefaultLength(int Caller, TTrackElement &TrackElement, bool FirstTrack, bool &LengthDifferent, bool &SpeedDifferent)
8347 /* FirstTrack = LinkPos's 0 & 1
8348  Examine track within TrackElement & check whether it has the default length and speed limit, return true if so
8349 */
8350 {
8351  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsElementTrackDefaultLength," + TrackElement.LogTrack(10) + "," +
8352  AnsiString((short)FirstTrack));
8353  LengthDifferent = false;
8354  SpeedDifferent = false;
8355  if(((TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Points) || (TrackElement.TrackType == Crossover)) && FirstTrack)
8356  {
8357  if(TrackElement.Length01 != DefaultTrackLength)
8358  {
8359  LengthDifferent = true;
8360  }
8361  if(TrackElement.SpeedLimit01 != DefaultTrackSpeedLimit)
8362  {
8363  SpeedDifferent = true;
8364  }
8365  if(LengthDifferent || SpeedDifferent)
8366  {
8367  Utilities->CallLogPop(625);
8368  return false;
8369  }
8370  Utilities->CallLogPop(626);
8371  return true;
8372  }
8373 
8374  else if(((TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Points) || (TrackElement.TrackType == Crossover)) && !FirstTrack)
8375  {
8376  if(TrackElement.Length23 != DefaultTrackLength)
8377  {
8378  LengthDifferent = true;
8379  }
8380  if(TrackElement.SpeedLimit23 != DefaultTrackSpeedLimit)
8381  {
8382  SpeedDifferent = true;
8383  }
8384  if(LengthDifferent || SpeedDifferent)
8385  {
8386  Utilities->CallLogPop(627);
8387  return false;
8388  }
8389  Utilities->CallLogPop(628);
8390  return true;
8391  }
8392 
8393  else // any other 1 track element, including platforms being present
8394  {
8395  if(TrackElement.Length01 != DefaultTrackLength)
8396  {
8397  LengthDifferent = true;
8398  }
8399  if(TrackElement.SpeedLimit01 != DefaultTrackSpeedLimit)
8400  {
8401  SpeedDifferent = true;
8402  }
8403  if(LengthDifferent || SpeedDifferent)
8404  {
8405  Utilities->CallLogPop(629);
8406  return false;
8407  }
8408  Utilities->CallLogPop(630);
8409  return true;
8410  }
8411 }
8412 
8413 // ---------------------------------------------------------------------------
8414 
8415 bool TTrack::IsPlatformOrNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
8416  // Check whether there is a platform or NamedNonStationLocation present at HLoc & VLoc, return true if so
8417 {
8418  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsPlatformOrNamedNonStationLocationPresent," + AnsiString(HLoc) + "," +
8419  AnsiString(VLoc));
8420  bool FoundFlag;
8421  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(11, HLoc, VLoc, FoundFlag);
8422 
8423  if(!FoundFlag)
8424  {
8425  Utilities->CallLogPop(633);
8426  return false;
8427  }
8428  if((InactiveTrackElementAt(42, IMPair.first).TrackType == Platform) || (InactiveTrackElementAt(91, IMPair.first).TrackType == NamedNonStationLocation))
8429  {
8430  Utilities->CallLogPop(634);
8431  return true; // only need to check first since if second is a platform the the first must be too
8432  }
8433  else
8434  {
8435  Utilities->CallLogPop(635);
8436  return false;
8437  }
8438 }
8439 
8440 // ---------------------------------------------------------------------------
8441 
8442 bool TTrack::IsNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
8443  // Check whether there is a NamedNonStationLocation present at HLoc & VLoc, return true if so
8444 {
8445  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsNamedNonStationLocationPresent," + AnsiString(HLoc) + "," +
8446  AnsiString(VLoc));
8447  bool FoundFlag;
8448  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(12, HLoc, VLoc, FoundFlag);
8449 
8450  if(!FoundFlag)
8451  {
8452  Utilities->CallLogPop(636);
8453  return false;
8454  }
8456  {
8457  Utilities->CallLogPop(637);
8458  return true; // only need to check first since only one used for NamedNonStationLocations
8459  }
8460  else
8461  {
8462  Utilities->CallLogPop(638);
8463  return false;
8464  }
8465 }
8466 
8467 // ---------------------------------------------------------------------------
8468 
8470 /* Called when trying to link track and when a name changed when track already linked. Examines all track elements that
8471  have ActiveTrackElementName set, sums the number of consecutive elements with the same name, and sets the EntryLink values for
8472  the front of train stop points for each direction.
8473  For stations (not non-station named locations) of length n, where n > 1, stop element is [floor((n+1)/2) + 1] from each
8474  end (unless buffers at one or both ends in which case stop points are the end elements).
8475  Note that for a single element the stop point is the element itself (formula doesn't apply).
8476  During the function the StationEntryStopLink values are set to 5 if not used, so no need to keep
8477  repeating the procedure for every element. At the end all unused values are returned to -1.
8478  For NamedNonStationLocations the stop points are at the end elements to allow trains to stack up.
8479 */
8480 {
8481  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetStationEntryStopLinkPosses");
8482  TTrackElement TempElement, StartElement;
8483  AnsiString TempName;
8484  int VecPos, StartVecPos, Count, EntryPos, StartEntryPos, ForwardNumber, ReverseNumber;
8485  bool ForwardSet, ReverseSet;
8486 
8487  for(unsigned int x = 0; x < TrackVector.size(); x++)
8488  {
8489  TrackVector.at(x).StationEntryStopLinkPos1 = -1;
8490  TrackVector.at(x).StationEntryStopLinkPos2 = -1;
8491  }
8492  for(unsigned int x = 0; x < TrackVector.size(); x++)
8493  {
8494  ForwardSet = false;
8495  ReverseSet = false;
8496  TempElement = TrackVector.at(x);
8497  VecPos = x;
8498  if((TempElement.ActiveTrackElementName != "") && (TempElement.StationEntryStopLinkPos1 == -1))
8499  // 2nd condition incl so don't re-examine elements with stop links set to 5
8500  {
8501  TempName = TempElement.ActiveTrackElementName;
8502  if((TempElement.Conn[0] > -1) && (TempElement.Conn[1] > -1) && (TrackElementAt(44, TempElement.Conn[0]).ActiveTrackElementName == TempName) &&
8503  (TrackElementAt(45, TempElement.Conn[1]).ActiveTrackElementName == TempName))
8504  // an element linked at both ends where both links are also named elements
8505  // only Conn[0] & [1] relevant for ActiveTrackElementName elements (only 2-track named element is points, and only straight track relevant & this has 0 & 1 as entry/exit positions)
8506  {
8507  continue; // looking for an end element so skip this one
8508  }
8509  else // reached one end
8510  {
8511  if((TempElement.Conn[0] > -1) && (TempElement.Conn[1] > -1) && (TrackElementAt(46, TempElement.Conn[0]).ActiveTrackElementName != TempName) &&
8512  (TrackElementAt(47, TempElement.Conn[1]).ActiveTrackElementName != TempName))
8513  // single named element linked at both ends
8514  {
8515  TrackElementAt(48, VecPos).StationEntryStopLinkPos1 = 0;
8516  TrackElementAt(49, VecPos).StationEntryStopLinkPos2 = 1;
8517  continue;
8518  }
8519  else if((TempElement.TrackType == Buffers) && (TrackElementAt(618, TempElement.Conn[1]).ActiveTrackElementName != TempName))
8520  // single named buffer element (LinkPos 1 is the non-buffer end)
8521  {
8522  TrackElementAt(619, VecPos).StationEntryStopLinkPos1 = 0;
8523  TrackElementAt(620, VecPos).StationEntryStopLinkPos2 = 1;
8524  continue;
8525  }
8526  else
8527  // Note: only interested in connection positions 0 & 1 since all named elements are single track except points,
8528  // and platforms always on straight (conns 0 & 1) section of points
8529  {
8530  for(int y = 0; y < 2; y++)
8531  {
8532  int Dir = y; // Dir is the ExitPos of the element, towards the rest of the named elements
8533  // check for buffers at both ends - no need, function below now covers buffers at one & both ends
8534 /* TTrackElement Temp1 = TempElement;
8535  ***********New section, compiles but not checked - does bit below need to be else if?
8536  if((Temp1.TrackType == Buffers) && (Temp1.GetConfig(Dir) != End))
8537  {
8538  //search along Dir direction until find other end, skip if Dir facing buffer end
8539  int NewDir = Dir;
8540  int NewVecPos;
8541  while((Temp1.Conn[NewDir] > -1) && (TrackElementAt(598, Temp1.Conn[NewDir]).ActiveTrackElementName == TempName))
8542  {
8543  NewVecPos = Temp1.Conn[NewDir];
8544  NewDir = Track->GetNonPointsOppositeLinkPos(Temp1.ConnLinkPos[NewDir]);
8545  Temp1 = TrackElementAt(601, NewVecPos);
8546  }
8547  if((Temp1.Conn[NewDir] == -1) && (Temp1.TrackType == Buffers))
8548  {
8549  TrackElementAt(599, VecPos).StationEntryStopLinkPos1 = Dir;//EntryPos for train coming from other end is Dir
8550  TrackElementAt(600, NewVecPos).StationEntryStopLinkPos2 = 1 - NewDir;//For train moving in same direction as search direction its EntryPos == 1 - NewDir since NewDir is the ExitPos
8551  }
8552  }
8553  ***************
8554 */
8555  // end may be linked at both ends but only one link named, or buffer with linked element named
8556  // if a buffer then the named linkpos has to be 1
8557  // already dealt with all types of single element so at least 2 linked named element
8558  if(((TempElement.Conn[Dir] > -1) && (TempElement.Conn[1 - Dir] > -1) && (TrackElementAt(50,
8559  TempElement.Conn[1 - Dir]).ActiveTrackElementName != TempName)) || ((TempElement.TrackType == Buffers) && (Dir == 1)))
8560  {
8561  StartElement = TempElement;
8562  StartVecPos = VecPos;
8563  TrackElementAt(51, VecPos).StationEntryStopLinkPos1 = 5; // set to 5 to stop re-examination in later searches, all set back at end
8564  TrackElementAt(52, VecPos).StationEntryStopLinkPos2 = 5;
8565  EntryPos = 1 - Dir;
8566  StartEntryPos = 1 - Dir;
8567  Count = 1;
8568  // work along named elements until find the other end
8569  while((TempElement.Conn[1 - EntryPos] > -1) && (TrackElementAt(53,
8570  TempElement.Conn[1 - EntryPos]).ActiveTrackElementName == TempName))
8571  // at end of 'while' Count = length (in elements) of platform/nonstationloc, VecPos = vector number of far end
8572  // which is the last named element that is track-linked to the rest of the location, it may be a buffer
8573  // all stop link pos's are set to 5
8574  {
8575  VecPos = TempElement.Conn[1 - EntryPos];
8576  int TempEntryPos = TempElement.ConnLinkPos[1 - EntryPos];
8577  TempElement = TrackElementAt(54, TempElement.Conn[1 - EntryPos]);
8578  EntryPos = TempEntryPos;
8579  Count++;
8580  TrackElementAt(55, VecPos).StationEntryStopLinkPos1 = 5;
8581  TrackElementAt(56, VecPos).StationEntryStopLinkPos2 = 5;
8582  }
8583  // here when reached other end, maybe buffers, continuation or last named linked element
8584  if(TrackElementAt(57, VecPos).TrackType == Buffers)
8585  // terminal station, set end elements as stop elements
8586  {
8587  TrackElementAt(58, VecPos).StationEntryStopLinkPos1 = EntryPos;
8588  TrackElementAt(59, StartVecPos).StationEntryStopLinkPos2 = 1 - StartEntryPos; // for train leaving
8589  continue;
8590  }
8591  if(TrackElementAt(60, StartVecPos).TrackType == Buffers) // best not to use 'else if' as both ends could be buffers!
8592  // terminal station, set end elements as stop elements
8593  {
8594  TrackElementAt(61, VecPos).StationEntryStopLinkPos1 = EntryPos;
8595  TrackElementAt(62, StartVecPos).StationEntryStopLinkPos2 = 1 - StartEntryPos;
8596  continue;
8597  }
8598  if(IsNamedNonStationLocationPresent(1, TrackElementAt(63, StartVecPos).HLoc, TrackElementAt(64, StartVecPos).VLoc))
8599  // NonStationLocation so set end elements as stop elements
8600  {
8601  TrackElementAt(65, VecPos).StationEntryStopLinkPos1 = EntryPos;
8602  TrackElementAt(66, StartVecPos).StationEntryStopLinkPos2 = 1 - StartEntryPos;
8603  continue;
8604  }
8605  // now Count == length of platform, can calculate StationEntryStopLinkPos values and the elements to which they apply
8606  ForwardNumber = ((Count + 1) / 2) + 1;
8607  ReverseNumber = (Count - ForwardNumber) + 1;
8608  Count = 1; // starting value
8609  EntryPos = 1 - Dir;
8610  TempElement = StartElement;
8611  VecPos = StartVecPos;
8612  if(Count == ForwardNumber)
8613  {
8614  TrackElementAt(67, VecPos).StationEntryStopLinkPos1 = EntryPos;
8615  ForwardSet = true;
8616  }
8617  if(Count == ReverseNumber) // don't use 'else' as may both be at same element
8618  {
8619  TrackElementAt(68, VecPos).StationEntryStopLinkPos2 = 1 - EntryPos;
8620  ReverseSet = true;
8621  }
8622  while((TempElement.Conn[1 - EntryPos] > -1) && (TrackElementAt(69,
8623  TempElement.Conn[1 - EntryPos]).ActiveTrackElementName == TempName) && (!ForwardSet || !ReverseSet))
8624  {
8625  VecPos = TempElement.Conn[1 - EntryPos];
8626  int TempEntryPos = TempElement.ConnLinkPos[1 - EntryPos];
8627  TempElement = TrackElementAt(70, TempElement.Conn[1 - EntryPos]);
8628  EntryPos = TempEntryPos;
8629  Count++;
8630  if(Count == ForwardNumber)
8631  {
8632  TrackElementAt(71, VecPos).StationEntryStopLinkPos1 = EntryPos;
8633  ForwardSet = true;
8634  }
8635  if(Count == ReverseNumber)
8636  {
8637  TrackElementAt(72, VecPos).StationEntryStopLinkPos2 = 1 - EntryPos;
8638  ReverseSet = true;
8639  }
8640  }
8641  }
8642  }
8643  }
8644  }
8645  }
8646  }
8647  for(unsigned int x = 0; x < TrackVector.size(); x++)
8648  {
8649  if(TrackVector.at(x).StationEntryStopLinkPos1 == 5)
8650  {
8651  TrackVector.at(x).StationEntryStopLinkPos1 = -1;
8652  }
8653  if(TrackVector.at(x).StationEntryStopLinkPos2 == 5)
8654  {
8655  TrackVector.at(x).StationEntryStopLinkPos2 = -1;
8656  }
8657  }
8658  Utilities->CallLogPop(639);
8659 }
8660 
8661 // ---------------------------------------------------------------------------
8662 
8663 void TTrack::PlotSmallRailway(int Caller, TDisplay *Disp)
8664 {
8665  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSmallRailway");
8666  TTrackElement Next;
8667 
8669  while(ReturnNextInactiveTrackElement(1, Next))
8670  {
8671  if(Next.SmallGraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
8672  {
8673  if(((Next.TrackType == Platform) || (Next.TrackType == Concourse) || (Next.TrackType == NamedNonStationLocation)) && (Next.LocationName == ""))
8674  // need striped graphics
8675  {
8676  if(Next.SpeedTag == 76)
8677  Disp->PlotSmallOutput(11, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm76striped);
8678  else if(Next.SpeedTag == 77)
8679  Disp->PlotSmallOutput(12, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm77striped);
8680  else if(Next.SpeedTag == 78)
8681  Disp->PlotSmallOutput(13, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm78striped);
8682  else if(Next.SpeedTag == 79)
8683  Disp->PlotSmallOutput(14, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm79striped);
8684  else if(Next.SpeedTag == 96)
8685  Disp->PlotSmallOutput(15, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm96striped);
8686  else if(Next.SpeedTag == 131)
8687  Disp->PlotSmallOutput(16, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm131striped);
8688  }
8689  else
8690  Disp->PlotSmallOutput(17, Next.HLoc * 4, (Next.VLoc * 4), Next.SmallGraphicPtr);
8691  }
8692  }
8693 
8694  NextTrackElementPtr = TrackVector.begin();
8695  while(ReturnNextTrackElement(1, Next))
8696  {
8697  if(Next.SmallGraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
8698  {
8699  if((Next.TrackType == FootCrossing) && (Next.LocationName == "")) // need striped graphics, use sm129 & 130 for 145 & 146
8700  {
8701  if((Next.SpeedTag == 129) || (Next.SpeedTag == 145))
8702  Disp->PlotSmallOutput(18, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm129striped);
8703  else if((Next.SpeedTag == 130) || (Next.SpeedTag == 146))
8704  Disp->PlotSmallOutput(19, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm130striped);
8705  }
8706  else
8707  Disp->PlotSmallOutput(20, Next.HLoc * 4, (Next.VLoc * 4), Next.SmallGraphicPtr);
8708  }
8709  }
8710  Disp->Update();
8711  Utilities->CallLogPop(640);
8712 }
8713 
8714 // ---------------------------------------------------------------------------
8715 
8716 void TTrack::PlotSmallRedGap(int Caller)
8717 {
8718  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSmallRedGap");
8720  Utilities->CallLogPop(1346);
8721 }
8722 
8723 // ---------------------------------------------------------------------------
8724 
8725 void TTrack::TrackClear(int Caller)
8726 {
8727  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackClear");
8728  TrackVector.clear();
8729  InactiveTrackVector.clear();
8730  TrackMap.clear();
8732  if(TextHandler->TextVector.size() == 0)
8733  {
8734  Display->DisplayOffsetH = 0;
8735  Display->DisplayOffsetV = 0;
8742  HLocMin = 2000000000;
8743  HLocMax = -2000000000;
8744  VLocMin = 2000000000;
8745  VLocMax = -2000000000;
8746  }
8747  else
8748  CalcHLocMinEtc(4);
8749  Utilities->CallLogPop(1347);
8750 }
8751 
8752 // ---------------------------------------------------------------------------
8753 
8754 void TTrack::CalcHLocMinEtc(int Caller)
8755 {
8756  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CalcHLocMinEtc");
8757  HLocMin = 2000000000;
8758  VLocMin = 2000000000;
8759  HLocMax = -2000000000;
8760  VLocMax = -2000000000;
8761  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
8762  {
8763  if(TrackVector.at(x).SpeedTag == 0)
8764  continue; // skip erase elements or would interfere with Min & Max values
8765  if(TrackVector.at(x).HLoc - 1 < HLocMin)
8766  HLocMin = TrackVector.at(x).HLoc - 1; // add one all round
8767  if(TrackVector.at(x).HLoc + 1 > HLocMax)
8768  HLocMax = TrackVector.at(x).HLoc + 1;
8769  if(TrackVector.at(x).VLoc - 1 < VLocMin)
8770  VLocMin = TrackVector.at(x).VLoc - 1;
8771  if(TrackVector.at(x).VLoc + 1 > VLocMax)
8772  VLocMax = TrackVector.at(x).VLoc + 1;
8773  }
8774  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++) // check all elements in turn
8775  {
8776  if(InactiveTrackVector.at(x).SpeedTag == 0)
8777  continue; // shouldn't be any inactive erase elements but include anyway
8778  if(InactiveTrackVector.at(x).HLoc - 1 < HLocMin)
8779  HLocMin = InactiveTrackVector.at(x).HLoc - 1; // add one all round
8780  if(InactiveTrackVector.at(x).HLoc + 1 > HLocMax)
8781  HLocMax = InactiveTrackVector.at(x).HLoc + 1;
8782  if(InactiveTrackVector.at(x).VLoc - 1 < VLocMin)
8783  VLocMin = InactiveTrackVector.at(x).VLoc - 1;
8784  if(InactiveTrackVector.at(x).VLoc + 1 > VLocMax)
8785  VLocMax = InactiveTrackVector.at(x).VLoc + 1;
8786  }
8787  for(unsigned int x = 0; x < TextHandler->TextVectorSize(10); x++) // check all elements in turn
8788  {
8789 /* Removed at v2.2.0: It isn't needed because null names aren't entered into vector, and in any case if were then
8790  will fail as x will exceed the maximum value
8791  if(TextHandler->TextPtrAt(34, x)->TextString == "")
8792  {
8793  TextHandler->TextErase(8, TextHandler->TextPtrAt(35, x)->HPos, TextHandler->TextPtrAt(36, x)->VPos);
8794  }
8795 */
8796  int TextH = TextHandler->TextPtrAt(0, x)->HPos, TextV = TextHandler->TextPtrAt(1, x)->VPos;
8797  if((TextH / 16) - 1 < HLocMin)
8798  HLocMin = (TextH / 16) - 1; // integer division will truncate so subtract 1 to ensure include the start
8799  if((TextH / 16) + 1 > HLocMax)
8800  HLocMax = (TextH / 16) + 1; // integer division will truncate so add 1 to ensure include the start
8801  if((TextV / 16) - 1 < VLocMin)
8802  VLocMin = (TextV / 16) - 1;
8803  if((TextV / 16) + 1 > VLocMax)
8804  VLocMax = (TextV / 16) + 1;
8805  }
8806  for(unsigned int x = 0; x < UserGraphicVector.size(); x++) // added at v2.4.0
8807  {
8808  if((UserGraphicVectorAt(5, x).HPos / 16) - 1 < HLocMin)
8809  HLocMin = (UserGraphicVectorAt(6, x).HPos / 16) - 1; // add one all round
8810  if(((UserGraphicVectorAt(7, x).HPos + UserGraphicVectorAt(8, x).Width) / 16) + 1 > HLocMax)
8811  HLocMax = ((UserGraphicVectorAt(9, x).HPos + UserGraphicVectorAt(10, x).Width) / 16) + 1;
8812  if((UserGraphicVectorAt(11, x).VPos / 16) - 1 < VLocMin)
8813  VLocMin = (UserGraphicVectorAt(12, x).VPos / 16) - 1;
8814  if(((UserGraphicVectorAt(13, x).VPos + UserGraphicVectorAt(14, x).Height) / 16) + 1 > VLocMax)
8815  VLocMax = ((UserGraphicVectorAt(15, x).VPos + UserGraphicVectorAt(16, x).Height) / 16) + 1;
8816  }
8817 
8818  Utilities->CallLogPop(641);
8819 }
8820 
8821 // ---------------------------------------------------------------------------
8822 
8823 void TTrack::UserGraphicMove(int Caller, int HPosInput, int VPosInput, int &UserGraphicItem, int &UserGraphicMoveHPos, int &UserGraphicMoveVPos,
8824  bool &UserGraphicFoundFlag)
8825 {
8826  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",UserGraphicMove," + AnsiString(HPosInput) + "," + AnsiString(VPosInput));
8827  TUserGraphicVector::iterator UserGraphicPtr;
8828 
8829  UserGraphicFoundFlag = false;
8830  if(!UserGraphicVector.empty())
8831  {
8832  int x = UserGraphicVector.size();
8833  for(UserGraphicPtr = (UserGraphicVector.end() - 1); UserGraphicPtr >= UserGraphicVector.begin(); UserGraphicPtr--)
8834  {
8835  x--;
8836  if((HPosInput >= (*UserGraphicPtr).HPos) && (HPosInput < ((*UserGraphicPtr).HPos + (*UserGraphicPtr).Width)) && (VPosInput >=
8837  (*UserGraphicPtr).VPos) && (VPosInput < ((*UserGraphicPtr).VPos + (*UserGraphicPtr).Height)))
8838  {
8839  UserGraphicItem = x;
8840  UserGraphicMoveHPos = (*UserGraphicPtr).HPos;
8841  UserGraphicMoveVPos = (*UserGraphicPtr).VPos;
8842  UserGraphicFoundFlag = true;
8843  Utilities->CallLogPop(2177);
8844  return;
8845  } // if ....
8846  } // for UserGraphicPtr...
8847  } // if !UserGraphicVector...
8848  Utilities->CallLogPop(2197);
8849 }
8850 
8851 // ---------------------------------------------------------------------------
8852 
8854 {
8855  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RetrieveStripedNamedLocationGraphicsWhereRelevant," +
8856  TrackElement.LogTrack(11));
8857  Graphics::TBitmap *GraphicOutput = RailGraphics->bmTransparentBgnd; // default value
8858  int SpeedTag = TrackElement.SpeedTag;
8859 
8860  if(SpeedTag < 1)
8861  {
8862  throw Exception("Error - SpeedTag value " + AnsiString(SpeedTag) + " in RetrieveStripedNamedLocationGraphicsWhereRelevant");
8863  }
8864  switch(SpeedTag)
8865  {
8866  case 76: // t platform
8867  GraphicOutput = RailGraphics->gl76Striped;
8868  break;
8869 
8870  case 77: // h platform
8871  GraphicOutput = RailGraphics->bm77Striped;
8872  break;
8873 
8874  case 78: // v platform
8875  GraphicOutput = RailGraphics->bm78Striped;
8876  break;
8877 
8878  case 79: // r platform
8879  GraphicOutput = RailGraphics->gl79Striped;
8880  break;
8881 
8882  case 96: // concourse
8883  GraphicOutput = RailGraphics->ConcourseStriped;
8884  break;
8885 
8886  case 129: // v footbridge
8887  GraphicOutput = RailGraphics->gl129Striped;
8888  break;
8889 
8890  case 130: // h footbridge
8891  GraphicOutput = RailGraphics->gl130Striped;
8892  break;
8893 
8894  case 131: // non-station named loc
8895  GraphicOutput = RailGraphics->bmNameStriped;
8896  break;
8897 
8898  case 145: // v u'pass
8899  GraphicOutput = RailGraphics->gl145Striped;
8900  break;
8901 
8902  case 146: // h u'pass
8903  GraphicOutput = RailGraphics->gl146Striped;
8904  break;
8905 
8906  default:
8907  GraphicOutput = TrackElement.GraphicPtr;
8908  break;
8909  }
8910  Utilities->CallLogPop(642);
8911  return GraphicOutput;
8912 }
8913 
8914 // ---------------------------------------------------------------------------
8915 
8917 {
8918  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackElementAt," + AnsiString(At));
8919  if((At < 0) || ((unsigned int)At >= TrackVector.size()))
8920  {
8921  throw Exception("Out of Range Error, vector size: " + AnsiString(TrackVector.size()) + ", At: " + AnsiString(At) + " in TrackElementAt");
8922  }
8923  Utilities->CallLogPop(643);
8924  return TrackVector.at(At);
8925 }
8926 
8927 // ---------------------------------------------------------------------------
8928 
8930 {
8931  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",InactiveTrackElementAt," + AnsiString(At));
8932  if((At < 0) || ((unsigned int)At >= InactiveTrackVector.size()))
8933  {
8934  throw Exception("Out of Range Error, vector size: " + AnsiString(InactiveTrackVector.size()) + ", At: " + AnsiString(At) +
8935  " in InactiveTrackElementAt");
8936  }
8937  Utilities->CallLogPop(644);
8938  return InactiveTrackVector.at(At);
8939 }
8940 
8941 // ---------------------------------------------------------------------------
8942 
8943 bool TTrack::BlankElementAt(int Caller, int At) const
8944 {
8945  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",BlankElementAt," + AnsiString(At));
8946  if((At < 0) || ((unsigned int)At >= TrackVector.size()))
8947  {
8948  throw Exception("Out of Range Error, vector size: " + AnsiString(TrackVector.size()) + ", At: " + AnsiString(At) + " in BlankElementAt");
8949  }
8950  if(TrackVector.at(At).SpeedTag == 0)
8951  {
8952  Utilities->CallLogPop(645);
8953  return true;
8954  }
8955  else
8956  {
8957  Utilities->CallLogPop(646);
8958  return false;
8959  }
8960 }
8961 
8962 // ---------------------------------------------------------------------------
8963 
8964 bool TTrack::OneNamedLocationLongEnoughForSplit(int Caller, AnsiString LocationName)
8965 /* Check sufficient elements with same ActiveTrackElementName linked together without any trailing point links to allow a train split.
8966  Only one length is needed to return true, but this doesn't mean that all platforms at the location are long enough. When a
8967  split is required a specific check is made using ThisNamedLocationLongEnoughForSplit.
8968  Need at least two linked ActiveTrackElementNames, with connected elements at each end, which may or may not be ActiveTrackElementNames,
8969  and no connections via point trailing links. Note that these conditions exclude opposed buffers since these not linked.
8970 */
8971 {
8972  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",OneNamedLocationLongEnoughForSplit," + LocationName);
8973  TTrackElement InactiveElement, FirstNamedElement, SecondNamedElement, FirstNamedLinkedElement, SecondNamedLinkedElement;
8974  int FirstNamedExitPos, SecondNamedExitPos, FirstNamedLinkedExitPos, SecondNamedLinkedEntryPos;
8975  TLocationNameMultiMapIterator SNIterator;
8976  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
8977 
8978  if(SNRange.first == SNRange.second)
8979  {
8980  Utilities->CallLogPop(972);
8981  return false; // should have been caught earlier but include for completeness
8982  }
8983  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
8984  {
8985  if(SNIterator->second < 0)
8986  continue; // exclude footcrossings
8987  InactiveElement = InactiveTrackElementAt(47, SNIterator->second);
8988  if(InactiveElement.TrackType == Concourse)
8989  continue; // only interested in locations where ActiveTrackElementName may be set
8990  THVPair HVPair;
8991  HVPair.first = InactiveElement.HLoc;
8992  HVPair.second = InactiveElement.VLoc;
8993  if(TrackMap.find(HVPair) == TrackMap.end())
8994  {
8995  throw Exception
8996  ("Error - failed to find element in TrackMap for a non-concourse element in LocationNameMultiMap in OneNamedLocationLongEnoughForSplit (1)");
8997  }
8998  int TVPos = TrackMap.find(HVPair)->second;
8999  FirstNamedElement = TrackElementAt(560, TVPos);
9000  // first check linked on both sides, skip the check if not
9001  if((FirstNamedElement.Conn[0] == -1) || (FirstNamedElement.Conn[1] == -1))
9002  {
9003  continue;
9004  }
9005  // check if another ActiveTrackElementName connected via link pos 0 (can only be 0 or 1 since the only 2-track elements that can be
9006  // ActiveTrackElementNames are points and excluding trailing connections for points
9007  FirstNamedExitPos = 0;
9008  {
9009  SecondNamedElement = TrackElementAt(561, FirstNamedElement.Conn[FirstNamedExitPos]);
9010  SecondNamedExitPos = GetNonPointsOppositeLinkPos(FirstNamedElement.ConnLinkPos[FirstNamedExitPos]);
9011  FirstNamedLinkedElement = TrackElementAt(562, FirstNamedElement.Conn[1 - FirstNamedExitPos]);
9012  FirstNamedLinkedExitPos = FirstNamedElement.ConnLinkPos[1 - FirstNamedExitPos];
9013  if(SecondNamedElement.ActiveTrackElementName == LocationName) // success - check if it's connected on the far side
9014  {
9015  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
9016  {
9017  SecondNamedLinkedElement = TrackElementAt(563, SecondNamedElement.Conn[SecondNamedExitPos]);
9018  SecondNamedLinkedEntryPos = SecondNamedElement.ConnLinkPos[SecondNamedExitPos];
9019  if((SecondNamedLinkedElement.TrackType != Points) || (SecondNamedLinkedEntryPos != 3))
9020  // success, now check FirstNamedElement link not trailing points & if so all OK
9021  {
9022  if((FirstNamedLinkedElement.TrackType != Points) || (FirstNamedLinkedExitPos != 3))
9023  {
9024  Utilities->CallLogPop(1002);
9025  return true;
9026  }
9027  }
9028  }
9029  }
9030  }
9031  // failed, try link 1
9032  FirstNamedExitPos = 1;
9033  {
9034  SecondNamedElement = TrackElementAt(564, FirstNamedElement.Conn[FirstNamedExitPos]);
9035  SecondNamedExitPos = GetNonPointsOppositeLinkPos(FirstNamedElement.ConnLinkPos[FirstNamedExitPos]);
9036  FirstNamedLinkedElement = TrackElementAt(565, FirstNamedElement.Conn[1 - FirstNamedExitPos]);
9037  FirstNamedLinkedExitPos = FirstNamedElement.ConnLinkPos[1 - FirstNamedExitPos];
9038  if(SecondNamedElement.ActiveTrackElementName == LocationName) // success - check if it's connected on the far side
9039  {
9040  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
9041  {
9042  SecondNamedLinkedElement = TrackElementAt(566, SecondNamedElement.Conn[SecondNamedExitPos]);
9043  SecondNamedLinkedEntryPos = SecondNamedElement.ConnLinkPos[SecondNamedExitPos];
9044  if((SecondNamedLinkedElement.TrackType != Points) || (SecondNamedLinkedEntryPos != 3))
9045  // success, now check FirstNamedElement link not trailing points & if so all OK
9046  {
9047  if((FirstNamedLinkedElement.TrackType != Points) || (FirstNamedLinkedExitPos != 3))
9048  {
9049  Utilities->CallLogPop(1003);
9050  return true;
9051  }
9052  }
9053  }
9054  }
9055  }}
9056  Utilities->CallLogPop(1004);
9057  return false;
9058 }
9059 
9060 // ---------------------------------------------------------------------------
9061 bool TTrack::ThisNamedLocationLongEnoughForSplit(int Caller, AnsiString LocationName, int FirstNamedElementPos, int &SecondNamedElementPos,
9062  int &FirstNamedLinkedElementPos, int &SecondNamedLinkedElementPos)
9063  // for success need two linked named location elements, so that one element of each train can be at the location
9064  // FirstNamedElementPos is the input vector position and the first (if successful) of the two linked named location elements,
9065  // the second is SecondNamedElementPos, and the two linked elements are FirstNamedLinkedElementPos and SecondNamedLinkedElementPos.
9066  // the two trains will occupy these 4 elements
9067  // All are track vector positions, all but the input being references and set within the function.
9068 {
9069 /* Check sufficient elements (including TrackvectorPosition) with same ActiveTrackElementName linked together without any trailing point
9070  links and including the element FirstNamedElementPos to allow a train split. Need at least two linked ActiveTrackElementNames, with
9071  connected elements at each end, which may or may not be ActiveTrackElementNames, and no connections via point trailing links. Note that
9072  these conditions exclude opposed buffers since these not linked. Return the two train positions and exit positions for use in train
9073  splitting.
9074 */
9075  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ThisNamedLocationLongEnoughForSplit," + LocationName +
9076  AnsiString(FirstNamedElementPos));
9077  TTrackElement InactiveElement, FirstNamedElement, SecondNamedElement, FirstNamedLinkedElement, SecondNamedLinkedElement;
9078  int FirstNamedExitPos, SecondNamedExitPos, FirstNamedLinkedExitPos, SecondNamedLinkedEntryPos;
9079 
9080  SecondNamedElementPos = -1;
9081  FirstNamedLinkedElementPos = -1;
9082  SecondNamedLinkedElementPos = -1;
9083  TLocationNameMultiMapIterator SNIterator;
9084  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
9085 
9086  if(SNRange.first == SNRange.second) // i.e. location name not in map
9087  {
9088  Utilities->CallLogPop(1005);
9089  return false; // should have been caught earlier but include for completeness
9090  }
9091  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
9092  {
9093  if(SNIterator->second < 0)
9094  continue; // exclude footcrossings
9095  InactiveElement = InactiveTrackElementAt(69, SNIterator->second);
9096  if(InactiveElement.TrackType == Concourse)
9097  continue; // only interested in locations where ActiveTrackElementName may be set
9098  THVPair HVPair;
9099  HVPair.first = InactiveElement.HLoc;
9100  HVPair.second = InactiveElement.VLoc;
9101  if(TrackMap.find(HVPair) == TrackMap.end())
9102  {
9103  if(InactiveElement.TrackType == NamedNonStationLocation) // added at v2.2.0 to correct the error Xeon reported on 14/07/18.
9104  // If there is a NamedNonStationLocation without an associated active track element (effectively a non-station concourse)
9105  // then it won't be found in TrackMap but it's still legitimate.
9106  {
9107  continue;
9108  }
9109  else // for anything else throw the error
9110  {
9111  throw Exception
9112  ("Error - failed to find element in TrackMap for a non-concourse element in LocationNameMultiMap in ThisNamedLocationLongEnoughForSplit (2)"
9113  );
9114  }
9115  }
9116  int TVPos = TrackMap.find(HVPair)->second;
9117  if(TVPos != FirstNamedElementPos)
9118  continue; // looking for an exact match
9119  FirstNamedElement = TrackElementAt(567, TVPos);
9120  // first check linked on both sides, skip the check if not
9121  if((FirstNamedElement.Conn[0] == -1) || (FirstNamedElement.Conn[1] == -1))
9122  {
9123  continue;
9124  }
9125  // check if another ActiveTrackElementName connected via link pos 0 (can only be 0 or 1 since the only 2-track elements that can be
9126  // ActiveTrackElementNames are points and excluding trailing connections for points
9127  FirstNamedExitPos = 0;
9128  {
9129  SecondNamedElement = TrackElementAt(568, FirstNamedElement.Conn[FirstNamedExitPos]);
9130  SecondNamedExitPos = GetNonPointsOppositeLinkPos(FirstNamedElement.ConnLinkPos[FirstNamedExitPos]);
9131  FirstNamedLinkedElement = TrackElementAt(569, FirstNamedElement.Conn[1 - FirstNamedExitPos]);
9132  FirstNamedLinkedExitPos = FirstNamedElement.ConnLinkPos[1 - FirstNamedExitPos];
9133  if(SecondNamedElement.ActiveTrackElementName == LocationName) // success - check if it's connected on the far side
9134  {
9135  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
9136  {
9137  SecondNamedLinkedElement = TrackElementAt(570, SecondNamedElement.Conn[SecondNamedExitPos]);
9138  SecondNamedLinkedEntryPos = SecondNamedElement.ConnLinkPos[SecondNamedExitPos];
9139  if((SecondNamedLinkedElement.TrackType != Points) || (SecondNamedLinkedEntryPos != 3))
9140  // success, now check FirstNamedElement link not trailing points & if so all OK
9141  {
9142  if((FirstNamedLinkedElement.TrackType != Points) || (FirstNamedLinkedExitPos != 3))
9143  {
9144  SecondNamedElementPos = FirstNamedElement.Conn[FirstNamedExitPos];
9145  FirstNamedLinkedElementPos = FirstNamedElement.Conn[1 - FirstNamedExitPos];
9146  SecondNamedLinkedElementPos = SecondNamedElement.Conn[SecondNamedExitPos];
9147  Utilities->CallLogPop(1006);
9148  return true;
9149  }
9150  }
9151  }
9152  }
9153  }
9154  // failed, try link 1
9155  FirstNamedExitPos = 1;
9156  {
9157  SecondNamedElement = TrackElementAt(571, FirstNamedElement.Conn[FirstNamedExitPos]);
9158  SecondNamedExitPos = GetNonPointsOppositeLinkPos(FirstNamedElement.ConnLinkPos[FirstNamedExitPos]);
9159  FirstNamedLinkedElement = TrackElementAt(572, FirstNamedElement.Conn[1 - FirstNamedExitPos]);
9160  FirstNamedLinkedExitPos = FirstNamedElement.ConnLinkPos[1 - FirstNamedExitPos];
9161  if(SecondNamedElement.ActiveTrackElementName == LocationName) // success - check if it's connected on the far side
9162  {
9163  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
9164  {
9165  SecondNamedLinkedElement = TrackElementAt(573, SecondNamedElement.Conn[SecondNamedExitPos]);
9166  SecondNamedLinkedEntryPos = SecondNamedElement.ConnLinkPos[SecondNamedExitPos];
9167  if((SecondNamedLinkedElement.TrackType != Points) || (SecondNamedLinkedEntryPos != 3))
9168  // success, now check FirstNamedElement link not trailing points & if so all OK
9169  {
9170  if((FirstNamedLinkedElement.TrackType != Points) || (FirstNamedLinkedExitPos != 3))
9171  {
9172  SecondNamedElementPos = FirstNamedElement.Conn[FirstNamedExitPos];
9173  FirstNamedLinkedElementPos = FirstNamedElement.Conn[1 - FirstNamedExitPos];
9174  SecondNamedLinkedElementPos = SecondNamedElement.Conn[SecondNamedExitPos];
9175  Utilities->CallLogPop(1007);
9176  return true;
9177  }
9178  }
9179  }
9180  }
9181  }}
9182  Utilities->CallLogPop(1008);
9183  return false;
9184 }
9185 
9186 // ---------------------------------------------------------------------------
9187 
9188 bool TTrack::OneNamedLocationElementAtLocation(int Caller, AnsiString LocationName)
9189 {
9190  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",OneNamedLocationElementAtLocation," + LocationName);
9191  TLocationNameMultiMapIterator SNIterator;
9192  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
9193 
9194  if(SNRange.first != SNRange.second)
9195  {
9196  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
9197  {
9198  if(SNIterator->second < 0)
9199  continue; // only looking for inactive (platform or NamedNonStationLocation) elements
9200  if((InactiveTrackElementAt(33, SNIterator->second).TrackType == Platform) || (InactiveTrackElementAt(81,
9201  SNIterator->second).TrackType == NamedNonStationLocation))
9202  {
9203  Utilities->CallLogPop(1121);
9204  return true;
9205  }
9206  }
9207  }
9208  Utilities->CallLogPop(848);
9209  return false;
9210 }
9211 
9212 // ---------------------------------------------------------------------------
9213 
9214 bool TTrack::PlatformOnSignalSide(int Caller, int HLoc, int VLoc, int SpeedTag, Graphics::TBitmap* &SignalPlatformGraphic)
9215 {
9216 // dropped special platforms at v0.6 as didn't show well against ground signals & not needed anyway as plats always plotted first where there are signals
9217  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlatformOnSignalSide," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
9218  "," + AnsiString(SpeedTag));
9219  if(!IsPlatformOrNamedNonStationLocationPresent(5, HLoc, VLoc)) // can't be a named location so no ambiguity
9220  {
9221  Utilities->CallLogPop(949);
9222  return false;
9223  }
9224  bool FoundFlag;
9225  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(27, HLoc, VLoc, FoundFlag);
9226 
9227  if(!FoundFlag)
9228  {
9229  throw Exception("Error, FoundFlag false in PlatformOnSignalSide after IsPlatformOrNamedNonStationLocationPresent called successfully");
9230  }
9231  TTrackElement IAElement;
9232 
9233  if(SpeedTag == 68) // top sig
9234  {
9235  if((InactiveTrackElementAt(22, IMPair.first).SpeedTag == 76) || (InactiveTrackElementAt(23, IMPair.second).SpeedTag == 76)) // top plat
9236  {
9237  if(InactiveTrackElementAt(49, IMPair.first).SpeedTag == 76)
9238  IAElement = InactiveTrackElementAt(50, IMPair.first);
9239  else
9240  IAElement = InactiveTrackElementAt(51, IMPair.second);
9241  if(IAElement.LocationName == "")
9242  {
9243 // SignalPlatformGraphic = RailGraphics->Plat68Striped;
9244  SignalPlatformGraphic = RailGraphics->gl76Striped;
9245  }
9246  else
9247  {
9248 // SignalPlatformGraphic = RailGraphics->Plat68;
9249  SignalPlatformGraphic = RailGraphics->gl76;
9250  }
9251  Utilities->CallLogPop(950);
9252  return true;
9253  }
9254  }
9255  else if(SpeedTag == 69) // bot sig
9256  {
9257  if((InactiveTrackElementAt(70, IMPair.first).SpeedTag == 77) || (InactiveTrackElementAt(75, IMPair.second).SpeedTag == 77)) // bot plat
9258  {
9259  if(InactiveTrackElementAt(76, IMPair.first).SpeedTag == 77)
9260  IAElement = InactiveTrackElementAt(77, IMPair.first);
9261  else
9262  IAElement = InactiveTrackElementAt(78, IMPair.second);
9263  if(IAElement.LocationName == "")
9264  {
9265 // SignalPlatformGraphic = RailGraphics->Plat69Striped;
9266  SignalPlatformGraphic = RailGraphics->bm77Striped;
9267  }
9268  else
9269  {
9270 // SignalPlatformGraphic = RailGraphics->Plat69;
9271  SignalPlatformGraphic = RailGraphics->bm77;
9272  }
9273  Utilities->CallLogPop(951);
9274  return true;
9275  }
9276  }
9277  else if(SpeedTag == 70) // left sig
9278  {
9279  if((InactiveTrackElementAt(52, IMPair.first).SpeedTag == 78) || (InactiveTrackElementAt(79, IMPair.second).SpeedTag == 78)) // left plat
9280  {
9281  if(InactiveTrackElementAt(80, IMPair.first).SpeedTag == 78)
9282  IAElement = InactiveTrackElementAt(55, IMPair.first);
9283  else
9284  IAElement = InactiveTrackElementAt(82, IMPair.second);
9285  if(IAElement.LocationName == "")
9286  {
9287 // SignalPlatformGraphic = RailGraphics->Plat70Striped;
9288  SignalPlatformGraphic = RailGraphics->bm78Striped;
9289  }
9290  else
9291  {
9292 // SignalPlatformGraphic = RailGraphics->Plat70;
9293  SignalPlatformGraphic = RailGraphics->bm78;
9294  }
9295  Utilities->CallLogPop(952);
9296  return true;
9297  }
9298  }
9299  else if(SpeedTag == 71) // right sig
9300  {
9301  if((InactiveTrackElementAt(83, IMPair.first).SpeedTag == 79) || (InactiveTrackElementAt(58, IMPair.second).SpeedTag == 79)) // right plat
9302  {
9303  if(InactiveTrackElementAt(84, IMPair.first).SpeedTag == 79)
9304  IAElement = InactiveTrackElementAt(85, IMPair.first);
9305  else
9306  IAElement = InactiveTrackElementAt(86, IMPair.second);
9307  if(IAElement.LocationName == "")
9308  {
9309 // SignalPlatformGraphic = RailGraphics->Plat71Striped;
9310  SignalPlatformGraphic = RailGraphics->gl79Striped;
9311  }
9312  else
9313  {
9314 // SignalPlatformGraphic = RailGraphics->Plat71;
9315  SignalPlatformGraphic = RailGraphics->gl79;
9316  }
9317  Utilities->CallLogPop(953);
9318  return true;
9319  }
9320  }
9321  Utilities->CallLogPop(954);
9322  return false;
9323 }
9324 
9325 // ---------------------------------------------------------------------------
9326 
9327 bool TTrack::OtherTrainOnTrack(int Caller, int NextPos, int NextEntryPos, int OwnTrainID)
9328  // returns true if another train on NextEntryPos track of element at NextPos, whether bridge or not
9329  // false if not, if NextPos == -1, or if only own train on the track
9330 {
9331  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",OtherTrainOnTrack," + AnsiString(NextPos) + "," +
9332  AnsiString(NextEntryPos) + "," + AnsiString(OwnTrainID));
9333  if(NextEntryPos < 0)
9334  {
9335  Utilities->CallLogPop(1348);
9336  return false;
9337  }
9338  TTrackElement TrackElement = TrackElementAt(713, NextPos);
9339 
9340  if(TrackElement.TrackType != Bridge)
9341  {
9342  Utilities->CallLogPop(1349);
9343  return ((TrackElement.TrainIDOnElement > -1) && (TrackElement.TrainIDOnElement != OwnTrainID));
9344  }
9345 // bridge if reach here
9346  if(NextEntryPos > 1)
9347  {
9348  Utilities->CallLogPop(1350);
9349  return ((TrackElement.TrainIDOnBridgeTrackPos23 > -1) && (TrackElement.TrainIDOnBridgeTrackPos23 != OwnTrainID));
9350  }
9351  else
9352  {
9353  Utilities->CallLogPop(1351);
9354  return ((TrackElement.TrainIDOnBridgeTrackPos01 > -1) && (TrackElement.TrainIDOnBridgeTrackPos01 != OwnTrainID));
9355  }
9356 }
9357 
9358 // ---------------------------------------------------------------------------
9359 
9361 {
9362  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SelectVectorAt," + AnsiString(At));
9363  if((At < 0) || ((unsigned int)At >= SelectVectorSize()))
9364  {
9365  throw Exception("Out of Range Error, vector size: " + AnsiString(TrackVector.size()) + ", At: " + AnsiString(At) + " in SelectVectorAt");
9366  }
9367  Utilities->CallLogPop(1483);
9368  return SelectVector.at(At);
9369 }
9370 
9371 // ---------------------------------------------------------------------------
9372 
9373 bool TTrack::IsATrackElementAdjacentToLink(int Caller, int HLocIn, int VLocIn, int LinkIn)
9374  // For element at HLoc & VLoc, returns true if there is an element adjacent to LinkIn
9375 {
9376  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsATrackElementAdjacentToLink," + AnsiString(HLocIn) + "," +
9377  AnsiString(VLocIn) + "," + AnsiString(LinkIn));
9378  bool FoundFlag = false;
9379  int NewHLoc = HLocIn + LinkHVArray[LinkIn][0];
9380  int NewVLoc = VLocIn + LinkHVArray[LinkIn][1];
9381 
9382  GetVectorPositionFromTrackMap(41, NewHLoc, NewVLoc, FoundFlag);
9383  Utilities->CallLogPop(1538);
9384  return FoundFlag;
9385 }
9386 
9387 // ---------------------------------------------------------------------------
9388 
9389 bool TTrack::FindHighestLowestAndLeftmostNamedElements(int Caller, AnsiString Name, int &VPosHi, int &VPosLo, int &HPos)
9390 {
9391 // return true if find an inactive element called 'Name'
9392  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindHighestAndLowestNamedElements," + Name);
9393  int VLocHi = -2000000000, VLocLo = 2000000000, HLoc = 2000000000;
9394  bool FoundFlag = false;
9395 
9396  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
9397  {
9398  if(InactiveTrackVector.at(x).LocationName == Name)
9399  {
9400  FoundFlag = true;
9401  int V = InactiveTrackVector.at(x).VLoc;
9402  int H = InactiveTrackVector.at(x).HLoc;
9403  if(V > VLocHi)
9404  VLocHi = V;
9405  if(V < VLocLo)
9406  VLocLo = V;
9407  if(H < HLoc)
9408  HLoc = H;
9409  }
9410  }
9411  if(FoundFlag)
9412  {
9413  VPosHi = 16 * VLocHi;
9414  VPosLo = 16 * VLocLo;
9415  HPos = 16 * HLoc;
9416  Utilities->CallLogPop(1562);
9417  return true;
9418  }
9419  else
9420  {
9421  Utilities->CallLogPop(1563);
9422  return false;
9423  }
9424 }
9425 
9426 // ---------------------------------------------------------------------------
9427 
9428 int TTrack::FindClosestLinkPosition(int Caller, int StartTVPosition, int EndTVPosition)
9429 {
9430 // return the link array position for the element at StartTVPosition that gives the closest link to the element at EndTVPosition
9431 // NB the StartTVPosition is expected to be a single track element as only positions 0 & 1 are checked
9432  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindClosestLinkPosition," + AnsiString(StartTVPosition) + "," +
9433  AnsiString(EndTVPosition));
9434  TTrackElement &StartElement = TrackElementAt(839, StartTVPosition);
9435  TTrackElement &EndElement = TrackElementAt(840, EndTVPosition);
9436 
9437 // get H & V values for the element adjacent to Link[0] & Link[1]
9438  int NewHLocLink0 = StartElement.HLoc + LinkHVArray[StartElement.Link[0]][0];
9439  int NewVLocLink0 = StartElement.VLoc + LinkHVArray[StartElement.Link[0]][1];
9440  int NewHLocLink1 = StartElement.HLoc + LinkHVArray[StartElement.Link[1]][0];
9441  int NewVLocLink1 = StartElement.VLoc + LinkHVArray[StartElement.Link[1]][1];
9442 
9443 // compute the sum of the squares of the H & V distances between EndElement and 'New' values
9444  int Link0Squares = ((EndElement.HLoc - NewHLocLink0) * (EndElement.HLoc - NewHLocLink0)) +
9445  ((EndElement.VLoc - NewVLocLink0) * (EndElement.VLoc - NewVLocLink0));
9446  int Link1Squares = ((EndElement.HLoc - NewHLocLink1) * (EndElement.HLoc - NewHLocLink1)) +
9447  ((EndElement.VLoc - NewVLocLink1) * (EndElement.VLoc - NewVLocLink1));
9448 
9449  if(Link0Squares <= Link1Squares)
9450  {
9451  Utilities->CallLogPop(1851);
9452  return 0;
9453  }
9454  else
9455  {
9456  Utilities->CallLogPop(1852);
9457  return 1;
9458  }
9459 }
9460 
9461 // ---------------------------------------------------------------------------
9462 
9463 int TTrack::GetAnyElementOppositeLinkPos(int Caller, int TrackVectorPosition, int LinkPos, bool &Derail)
9464 { // element can be points or any other type
9465  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetAnyElementOppositeLinkPos," + AnsiString(TrackVectorPosition) + "," +
9466  AnsiString(LinkPos));
9467  Derail = false;
9468  TTrackElement &TE = Track->TrackElementAt(277, TrackVectorPosition);
9469 
9470  if((TE.TrackType == Points) && (TE.Config[LinkPos] == Lead))
9471  {
9472  if(TE.Attribute == 0)
9473  {
9474  Utilities->CallLogPop(663);
9475  return 1; // Att == 0 & ExitPos == 1 represent straight
9476  }
9477  else
9478  {
9479  Utilities->CallLogPop(664);
9480  return 3; // Att == 1 & ExitPos == 3 represent diverging
9481  }
9482  }
9483  else if((TE.TrackType == Points) && (TE.Config[LinkPos] == Trail))
9484  {
9485  if((LinkPos == 1) && (TE.Attribute == 0))
9486  {
9487  Utilities->CallLogPop(665);
9488  return 0; // Att == 0 represents straight
9489  }
9490  else if(LinkPos == 1)
9491  {
9492  Derail = true;
9493  Utilities->CallLogPop(666);
9494  return 0;
9495  }
9496  else if((LinkPos == 3) && (TE.Attribute == 1))
9497  {
9498  Utilities->CallLogPop(667);
9499  return 0;
9500  }
9501  else if(LinkPos == 3)
9502  {
9503  Derail = true;
9504  Utilities->CallLogPop(668);
9505  return 0;
9506  }
9507  }
9508  else if(LinkPos == 0)
9509  {
9510  Utilities->CallLogPop(669);
9511  return 1;
9512  }
9513  else if(LinkPos == 1)
9514  {
9515  Utilities->CallLogPop(670);
9516  return 0;
9517  }
9518  else if(LinkPos == 2)
9519  {
9520  Utilities->CallLogPop(671);
9521  return 3;
9522  }
9523  else if(LinkPos == 3)
9524  {
9525  Utilities->CallLogPop(672);
9526  return 2;
9527  }
9528  throw Exception("Error, failure in GetExitPos"); // should never reach here
9529 }
9530 
9531 // ----------------------------------------------------------------------------
9532 
9534 {
9535  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PopulateLCVector");
9536  LCVector.clear();
9537  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
9538  {
9539  if(InactiveTrackVector.at(x).TrackType == LevelCrossing)
9540  {
9541  LCVector.push_back(x);
9542  }
9543  }
9544  Utilities->CallLogPop(1931);
9545  return;
9546 }
9547 
9548 // ---------------------------------------------------------------------------
9549 
9550 bool TTrack::TrainOnLink(int Caller, int HLoc, int VLoc, int Link, int &TrainID) // new at v1.2.0
9551 /*
9552  Call GetVectorPositionFromTrackMap to identify the track element, then check if TrainIDOnElement > -1 (if a
9553  bridge then check relevant TrainID according to the Link), and if absent return false. If present identify
9554  the train using TrainController->TrainVectorAtIdent, and check which bit on the element in question (Lead, Mid or Lag),
9555  and then check the relevant EntryPos & ExitPos for a match with Link. If find a match return true and return the TrainID.
9556 */
9557 {
9558  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrainOnLink," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
9559  AnsiString(Link));
9560  bool FoundFlag;
9561 
9562  TrainID = -1;
9563  int VecPos = GetVectorPositionFromTrackMap(47, HLoc, VLoc, FoundFlag);
9564 
9565  if(!FoundFlag)
9566  {
9567  Utilities->CallLogPop(2001);
9568  return false;
9569  }
9570  TTrackElement TE = TrackElementAt(882, VecPos);
9571 
9572  TrainID = TE.TrainIDOnElement;
9573  if(TE.TrackType == Bridge)
9574  {
9575  if(TE.TrainIDOnElement > -1)
9576  {
9577  if((TE.Link[0] == Link) || (TE.Link[1] == Link))
9578  {
9579  TrainID = TE.TrainIDOnBridgeTrackPos01;
9580  }
9581  else if((TE.Link[2] == Link) || (TE.Link[3] == Link))
9582  {
9583  TrainID = TE.TrainIDOnBridgeTrackPos23;
9584  }
9585  else
9586  TrainID = -1; // shouldn't ever reach here but be safe
9587  }
9588  }
9589  if(TrainID == -1)
9590  {
9591  Utilities->CallLogPop(2002);
9592  return false;
9593  }
9594 // now get the train
9595  TTrain Train = TrainController->TrainVectorAtIdent(38, TrainID);
9596 
9597  if(Train.LinkOccupied(0, VecPos, Link)) // checks whether any part of train occupying Link on VecPos
9598  {
9599  Utilities->CallLogPop(2003);
9600  return true;
9601  }
9602  TrainID = -1;
9603  Utilities->CallLogPop(2004);
9604  return false;
9605 }
9606 
9607 // ---------------------------------------------------------------------------
9608 bool TTrack::DiagonalFouledByTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber, int &TrainID)
9609 /* New at v1.2.0
9610  As DiagonalFouledByRouteOrTarin but checks for a train only (may or may not be a route) and returns the ID number. Enter with H & V set for the element whose diagonal
9611  is to be checked, and the XLink number of the relevant diagonal, which must be 1, 3, 7 or 9.
9612  for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
9613  for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
9614  for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
9615  for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
9616  Each of these is examined in turn for each route element in the relevant position.
9617 */
9618 {
9619  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DiagonalFouledByTrain," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
9620  "," + AnsiString(DiagonalLinkNumber));
9621  TrainID = -1;
9622  TPrefDirElement TempPrefDirElement;
9623  TAllRoutes::TRouteElementPair FirstPair, SecondPair;
9624 
9625  if(((DiagonalLinkNumber == 1) && TrainOnLink(8, HLoc - 1, VLoc, 3, TrainID)) || ((DiagonalLinkNumber == 7) && TrainOnLink(9, HLoc - 1, VLoc, 9, TrainID)))
9626  {
9627  Utilities->CallLogPop(2027);
9628  return true;
9629  }
9630 
9631  if(((DiagonalLinkNumber == 1) && TrainOnLink(10, HLoc, VLoc - 1, 7, TrainID)) || ((DiagonalLinkNumber == 3) && TrainOnLink(11, HLoc, VLoc - 1, 9, TrainID)))
9632  {
9633  Utilities->CallLogPop(2028);
9634  return true;
9635  }
9636 
9637  if(((DiagonalLinkNumber == 3) && TrainOnLink(12, HLoc + 1, VLoc, 1, TrainID)) || ((DiagonalLinkNumber == 9) && TrainOnLink(13, HLoc + 1, VLoc, 7, TrainID)))
9638  {
9639  Utilities->CallLogPop(2029);
9640  return true;
9641  }
9642 
9643  if(((DiagonalLinkNumber == 7) && TrainOnLink(14, HLoc, VLoc + 1, 1, TrainID)) || ((DiagonalLinkNumber == 9) && TrainOnLink(15, HLoc, VLoc + 1, 3, TrainID)))
9644  {
9645  Utilities->CallLogPop(2030);
9646  return true;
9647  }
9648 
9649  Utilities->CallLogPop(2031);
9650  return false;
9651 }
9652 
9653 // ---------------------------------------------------------------------------
9654 
9655 void TTrack::SaveUserGraphics(int Caller, std::ofstream &VecFile)
9656 {
9657  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveUserGraphics");
9658  Utilities->SaveFileInt(VecFile, UserGraphicVector.size()); // number of items
9659  TUserGraphicItem UGI;
9660  AnsiString JustFileName = "";
9661 
9662  for(unsigned int x = 0; x < UserGraphicVector.size(); x++)
9663  {
9664  UGI = UserGraphicVectorAt(17, x);
9665  int LastDelim = UGI.FileName.LastDelimiter('\\');
9666  if(LastDelim == 0) // can't find it so skip this item
9667  {
9668  continue;
9669  }
9670  else
9671  {
9672  JustFileName = UGI.FileName.SubString(LastDelim + 1, UGI.FileName.Length() - LastDelim);
9673  }
9674  Utilities->SaveFileString(VecFile, JustFileName);
9675  Utilities->SaveFileInt(VecFile, UGI.HPos);
9676  Utilities->SaveFileInt(VecFile, UGI.VPos);
9677  }
9678  Utilities->CallLogPop(2178);
9679 }
9680 
9681 // ---------------------------------------------------------------------------
9682 
9684 {
9685  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",UserGraphicVectorAt," + AnsiString(At));
9686  if((At < 0) || ((unsigned int)At >= UserGraphicVector.size()))
9687  {
9688  throw Exception("Out of Range Error, vector size: " + AnsiString(UserGraphicVector.size()) + ", At: " + AnsiString(At) + " in UserGraphicVectorAt");
9689  }
9690  Utilities->CallLogPop(2194);
9691  return UserGraphicVector.at(At);
9692 }
9693 
9694 // ---------------------------------------------------------------------------
9695 // PrefDir & Route functions
9696 // ---------------------------------------------------------------------------
9697 
9698 int TOnePrefDir::LastElementNumber(int Caller) const
9699 {
9700  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LastElementNumber,");
9701  int RetVal = PrefDirVector.size() - 1;
9702 
9703  if(RetVal < 0)
9704  {
9705  throw Exception("Return value negative in call to LastElementNumber");
9706  }
9707  Utilities->CallLogPop(114);
9708  return RetVal;
9709 }
9710 
9711 // ---------------------------------------------------------------------------
9713 {
9714  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LastElementPtr,");
9715  if(PrefDirVector.empty())
9716  {
9717  throw Exception("PrefDirVector empty in call to LastElementPtr");
9718  }
9719  TPrefDirVectorIterator RetIT = PrefDirVector.end() - 1;
9720 
9721  Utilities->CallLogPop(115);
9722  return RetIT;
9723 }
9724 
9725 // ---------------------------------------------------------------------------
9727 {
9728  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFixedPrefDirElementAt," + AnsiString(At));
9729  if((At < 0) || ((unsigned int)At >= PrefDirVector.size()))
9730  {
9731  throw Exception("Out of Range Error, vector size: " + AnsiString(PrefDirVector.size()) + ", At: " + AnsiString(At) + " in GetFixedPrefDirElementAt");
9732  }
9733  Utilities->CallLogPop(116);
9734  return PrefDirVector.at(At);
9735 }
9736 
9737 // ---------------------------------------------------------------------------
9739 {
9740  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetModifiablePrefDirElementAt," + AnsiString(At));
9741  if((At < 0) || ((unsigned int)At >= PrefDirVector.size()))
9742  {
9743  throw Exception("Out of Range Error, vector size: " + AnsiString(PrefDirVector.size()) + ", At: " + AnsiString(At) +
9744  " in GetModifiablePrefDirElementAt");
9745  }
9746  Utilities->CallLogPop(117);
9747  return PrefDirVector.at(At);
9748 }
9749 
9750 // ---------------------------------------------------------------------------
9752 {
9753  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFixedSearchElementAt," + AnsiString(At));
9754  if((At < 0) || ((unsigned int)At >= SearchVector.size()))
9755  {
9756  throw Exception("Out of Range Error, vector size: " + AnsiString(SearchVector.size()) + ", At: " + AnsiString(At) + " in GetFixedSearchElementAt");
9757  }
9758  Utilities->CallLogPop(118);
9759  return SearchVector.at(At);
9760 }
9761 
9762 // ---------------------------------------------------------------------------
9764 {
9765  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetModifiableSearchElementAt," + AnsiString(At));
9766  if((At < 0) || ((unsigned int)At >= SearchVector.size()))
9767  {
9768  throw Exception("Out of Range Error, vector size: " + AnsiString(SearchVector.size()) + ", At: " + AnsiString(At) + " in GetModifiableSearchElementAt");
9769  }
9770  Utilities->CallLogPop(119);
9771  return SearchVector.at(At);
9772 }
9773 
9774 // ---------------------------------------------------------------------------
9775 bool TOnePrefDir::GetPrefDirStartElement(int Caller, int HLoc, int VLoc) // Return true if OK.
9776 /*
9777  Enter with HLoc & VLoc set to selected element. Clear PrefDirVector, check if selected element
9778  is a valid track element & return false if not. Create a TPrefDirElement from the track element and
9779  set checkcount to 4 to cover the fixed values, then add to PrefDirVector. All variable values are
9780  set in later functions.
9781 */
9782 {
9783  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetPrefDirStartElement," + AnsiString(HLoc) + "," + AnsiString(VLoc));
9784  ClearPrefDir();
9785  int TrackVectorPosition;
9786  TTrackElement TrackElement;
9787 
9788  if(!(Track->FindNonPlatformMatch(5, HLoc, VLoc, TrackVectorPosition, TrackElement)))
9789  {
9790  Utilities->CallLogPop(126);
9791  return false;
9792  }
9793 /* it can be points so drop the code below - all exits are checked, no assumptions are made about the exit position of the start element
9794  if(TrackElement.TrackType == Points)
9795  {
9796  ShowMessage("Can't start on points");//because if PrefDir leads away from the leading edge
9797  //it isn't known which trailing edge is the required PrefDir - could use the straight as
9798  //default but may already be a PrefDir up to the diverging edge, then will have a mismatch,
9799  //best to prevent it to avoid problems
9800  Utilities->CallLogPop(127);
9801  return false;
9802  }
9803 */
9804  TPrefDirElement PrefDirElement(TrackElement);
9805 
9806  PrefDirElement.TrackVectorPosition = TrackVectorPosition;
9807  PrefDirElement.CheckCount = 4; // HLoc, VLoc, SpeedTag & TrackVectorPosition
9808  StorePrefDirElement(1, PrefDirElement); // enter first element
9809 // Note that ELink not set even if a buffer or continuation - these set in
9810 // ConvertPrefDirSearchVector after 2nd element added
9811 
9812  Utilities->CallLogPop(128);
9813  return true;
9814 }
9815 
9816 // ---------------------------------------------------------------------------
9817 bool TOnePrefDir::GetNextPrefDirElement(int Caller, int HLoc, int VLoc, bool &FinishElement)
9818 
9819 /*
9820  Enter with HLoc & VLoc set to selected element. If not a track element or if PrefDirVector empty return false.
9821  Examine the last element in the PrefDirvector, if ELink not set (start element) do an immediate
9822  check for an adjacent find (i.e. find selected element), & if succeed use SearchForPrefDir with that as XLinkPos to deal
9823  with setting the PrefDir vector, & return true. Also set FinishElement if found element was a buffer or continuation,
9824  so that the calling function knows that the PrefDir is complete.
9825  If last element was the start element but no immediate find, search on each valid exit pos in turn, using
9826  SearchForPrefDir to examine all branches. If succeed set PrefDirvector & finishelement as appropriate.
9827  Otherwise (last element not start element) check if last element was a leading point (if so can't be first element)
9828  & check again for an immediate find on either XLinkPos values 1 & 3, using SearchForPrefDir &
9829  ConvertPrefDirSearchVector to set PrefDirVector. Set FinishElement appropriately.
9830  If a leading point but not an immediate find use SearchForPrefDir on the XLinkPos values 1 & 3 in turn.
9831  If it wasn't a leading point just use XLinkPos value corresponding to XLink & Search on that. If don't
9832  find the required element return false. CheckCount is used to keep track of set values to allow check later.
9833 */
9834 
9835 {
9836  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetNextPrefDirElement," + AnsiString(HLoc) + "," + AnsiString(VLoc));
9837  FinishElement = false;
9838  int TrackVectorPosition;
9839 
9840  TotalSearchCount = 0;
9841  TTrackElement TrackElement, TempTrackElement;
9842 
9843  if(PrefDirVector.size() == 0)
9844  {
9845  Utilities->CallLogPop(129);
9846  return false;
9847  }
9848  if(!(Track->FindNonPlatformMatch(6, HLoc, VLoc, TrackVectorPosition, TrackElement)))
9849  {
9850  Utilities->CallLogPop(130);
9851  return false;
9852  }
9853 
9854 // set the search limits using the last stored element in PrefDirVector as the start point
9855 // set the H&V limits for the search, all points on search path must lie within 15 elements greater than the box of which the line between
9856 // start and finish is a diagonal line [dropped as not a good strategy because gaps interfered with direct line searches - instead
9857 // introduced TotalSearchCount and now use that to limit searches. Leave in though in case rethink strategy later on]
9858 
9859  TPrefDirElement StartPrefDirElement = PrefDirVector.at(LastElementNumber(72));
9860 
9861  if(TrackElement.HLoc >= StartPrefDirElement.HLoc)
9862  {
9863  SearchLimitLowH = StartPrefDirElement.HLoc - 15;
9864  SearchLimitHighH = TrackElement.HLoc + 15;
9865  }
9866  else
9867  {
9868  SearchLimitLowH = TrackElement.HLoc - 15;
9869  SearchLimitHighH = StartPrefDirElement.HLoc + 15;
9870  }
9871 
9872  if(TrackElement.VLoc >= StartPrefDirElement.VLoc)
9873  {
9874  SearchLimitLowV = StartPrefDirElement.VLoc - 15;
9875  SearchLimitHighV = TrackElement.VLoc + 15;
9876  }
9877  else
9878  {
9879  SearchLimitLowV = TrackElement.VLoc - 15;
9880  SearchLimitHighV = StartPrefDirElement.VLoc + 15;
9881  }
9882 /* dropped this for v0.4d - prevents ability to set paths for gaps that are widely separated, ok without it as search limited by SearchVector size
9883  check & TotalSearchCounts check
9884  if((abs(TrackElement.HLoc - StartPrefDirElement.HLoc) > 120) || (abs(TrackElement.VLoc - StartPrefDirElement.VLoc) > 120))
9885  {
9886  ShowMessage("Unable to reach the selected element - too far ahead");
9887  Utilities->CallLogPop(1692);
9888  return false;
9889  }
9890 */
9891 // get last PrefDir element
9892  if(PrefDirVector.at(LastElementNumber(0)).ELink == -1) // start element
9893  {
9894  // check if TrackElement adjacent to any of the 4 XLinkPos'
9895  for(int x = 0; x < 4; x++)
9896  {
9897  if(PrefDirVector.at(LastElementNumber(1)).Conn[x] == TrackVectorPosition)
9898  {
9899  PrefDirVector.at(LastElementNumber(2)).XLinkPos = x;
9900  PrefDirVector.at(LastElementNumber(3)).XLink = PrefDirVector.at(LastElementNumber(4)).Link[x];
9901  PrefDirVector.at(LastElementNumber(5)).CheckCount++;
9902  PrefDirVector.at(LastElementNumber(6)).CheckCount++;
9903  break; // can have 2 connections if have 2 adjacent gaps connected to each other but ELink & XLink
9904  // then ambiguous. Have to opt for just one, and if user wanted the other then that's unfortunate,
9905  // shouldn't ever get it in a serious railway though.
9906 // Note: ELink & ELinkPos are set in ConvertPrefDirSearchVector for the start element
9907  }
9908  }
9909  if(PrefDirVector.at(LastElementNumber(7)).XLinkPos > -1) // i.e required position must be adjacent to the start element
9910  {
9911  TempTrackElement = PrefDirVector.at(LastElementNumber(8));
9912  SearchVector.clear(); // use this & convert to set all PrefDir element values
9913  if(SearchForPrefDir(1, TempTrackElement, PrefDirVector.at(LastElementNumber(9)).XLinkPos, TrackVectorPosition))
9914  {
9916  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
9917  {
9918  FinishElement = true;
9919  }
9920  Utilities->CallLogPop(131);
9921  return true;
9922  }
9923  } // not an adjacent element
9924 
9925  // now check each of the 4 possible XLinkPos values
9926  for(int x = 0; x < 4; x++)
9927  {
9928  if((PrefDirVector.at(LastElementNumber(10)).Link[x] > 0) && (PrefDirVector.at(LastElementNumber(11)).Config[x] != End)) // i.e have somewhere to go
9929  {
9930  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find the required position
9931  TempTrackElement = PrefDirVector.at(LastElementNumber(12));
9932  SearchVector.clear();
9933  if(SearchForPrefDir(2, TempTrackElement, x, TrackVectorPosition))
9934  {
9936  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
9937  {
9938  FinishElement = true;
9939  }
9940  Utilities->CallLogPop(132);
9941  return true;
9942  }
9943  }
9944  } // here if checked all possible exits without success
9945  ShowMessage(
9946  "Unable to find a route to the selected element - may be unreachable, too far ahead, or invalid. Try selecting an end point closer to the start point.");
9947  Utilities->CallLogPop(133);
9948  return false;
9949  }
9950 // dealt above with LastPrefDirElement being the start element (which can be points)
9951 
9952  if((PrefDirVector.at(LastElementNumber(13)).TrackType == Points) && (PrefDirVector.at(LastElementNumber(14)).Config[PrefDirVector.at(LastElementNumber(15))
9953  .ELinkPos] == Lead)) // leading point
9954  {
9955  if(PrefDirVector.at(LastElementNumber(16)).Conn[1] == TrackVectorPosition) // found it next to XLinkPos = 1
9956  {
9957  PrefDirVector.at(LastElementNumber(17)).XLinkPos = 1;
9958  PrefDirVector.at(LastElementNumber(18)).XLink = PrefDirVector.at(LastElementNumber(19)).Link[1];
9959  // can't be buffers or gap if points
9960  PrefDirVector.at(LastElementNumber(20)).CheckCount++;
9961  PrefDirVector.at(LastElementNumber(21)).CheckCount++;
9962  TempTrackElement = PrefDirVector.at(LastElementNumber(22));
9963  SearchVector.clear();
9964  if(SearchForPrefDir(3, TempTrackElement, 1, TrackVectorPosition)) // bound to return true
9965  {
9967  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
9968  {
9969  FinishElement = true;
9970  }
9971  Utilities->CallLogPop(134);
9972  return true;
9973  }
9974  }
9975  if(PrefDirVector.at(LastElementNumber(23)).Conn[3] == TrackVectorPosition) // found it next to XLinkPos = 3
9976  {
9977  PrefDirVector.at(LastElementNumber(24)).XLinkPos = 3;
9978  PrefDirVector.at(LastElementNumber(25)).XLink = PrefDirVector.at(LastElementNumber(26)).Link[3];
9979  PrefDirVector.at(LastElementNumber(27)).CheckCount++;
9980  PrefDirVector.at(LastElementNumber(28)).CheckCount++;
9981  TempTrackElement = PrefDirVector.at(LastElementNumber(29));
9982  SearchVector.clear();
9983  if(SearchForPrefDir(4, TempTrackElement, 3, TrackVectorPosition)) // bound to return true
9984  {
9986  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
9987  {
9988  FinishElement = true;
9989  }
9990  Utilities->CallLogPop(135);
9991  return true;
9992  }
9993  }
9994 // above dealt with immediate finds for leading point,
9995 // now deal with ordinary searches for leading point
9996  PrefDirVector.at(LastElementNumber(30)).XLinkPos = 1;
9997  PrefDirVector.at(LastElementNumber(31)).XLink = PrefDirVector.at(LastElementNumber(32)).Link[1];
9998  PrefDirVector.at(LastElementNumber(33)).CheckCount++;
9999  PrefDirVector.at(LastElementNumber(34)).CheckCount++;
10000  TempTrackElement = PrefDirVector.at(LastElementNumber(35));
10001  SearchVector.clear();
10002  if(SearchForPrefDir(5, TempTrackElement, 1, TrackVectorPosition))
10003  {
10005  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
10006  {
10007  FinishElement = true;
10008  }
10009  Utilities->CallLogPop(136);
10010  return true;
10011  }
10012  PrefDirVector.at(LastElementNumber(36)).XLinkPos = 3;
10013  PrefDirVector.at(LastElementNumber(37)).XLink = PrefDirVector.at(LastElementNumber(38)).Link[3];
10014  // note that CheckCount already increased to allow for XLinkPos & XLink
10015  TempTrackElement = PrefDirVector.at(LastElementNumber(39));
10016  SearchVector.clear();
10017  if(SearchForPrefDir(6, TempTrackElement, 3, TrackVectorPosition))
10018  {
10020  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
10021  {
10022  FinishElement = true;
10023  }
10024  Utilities->CallLogPop(137);
10025  return true;
10026  }
10027 // here if failed to find match for leading point
10028  PrefDirVector.at(LastElementNumber(69)).CheckCount--; // to removed the earlier increments for XLinkPos & XLink
10029  PrefDirVector.at(LastElementNumber(70)).CheckCount--;
10030  ShowMessage(
10031  "Unable to find a route to the selected element - may be unreachable, too far ahead, or invalid. Try selecting an end point closer to the start point.");
10032  Utilities->CallLogPop(138);
10033  return false;
10034  }
10035 // leading point fully dealt with above
10036 // here with an ordinary element, just do an ordinary search - no need to search for an immediate find
10037 // separately as covered in ordinary search.
10038 
10039  TempTrackElement = PrefDirVector.at(LastElementNumber(40));
10040  SearchVector.clear();
10041 // no need to check for valid XLinkPos as not start element and not end element or would not reach here
10042  if(SearchForPrefDir(7, TempTrackElement, PrefDirVector.at(LastElementNumber(41)).XLinkPos, TrackVectorPosition))
10043  {
10045  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
10046  {
10047  FinishElement = true;
10048  }
10049  Utilities->CallLogPop(139);
10050  return true;
10051  }
10052  ShowMessage(
10053  "Unable to find a route to the selected element - may be unreachable, too far ahead, or invalid. Try selecting an end point closer to the start point.");
10054  Utilities->CallLogPop(140);
10055  return false; // failed to find required element
10056 }
10057 
10058 // ---------------------------------------------------------------------------
10059 
10060 bool TOnePrefDir::SearchForPrefDir(int Caller, TTrackElement CurrentTrackElement, int XLinkPos, int RequiredPosition)
10061 /*
10062  Enter with CurrentTrackElement stored in the PrefDirVector, XLinkPos set to the link
10063  to search on, & SearchVector cleared unless entered recursively. Function is a continuous loop that
10064  exits when find required element (returns true) or reaches a buffer or continuation or otherwise fails a search condition (returns false).
10065  Keep a count of entries in SearchVector during the current function call, so that this number can be
10066  erased for an unproductive branch search.
10067  Create a NextTrackElement from Current & XLinkPos as far as possible, & check if found required
10068  element. If so save it & return true. If not check if buffer, continuation, or earlier position
10069  in SearchVector or PrefDirVector, & if so erase all searchvector & return false. If OK check if a leading point and
10070  if so do up to 2 recursive searches for the 2 exits. If fail on both erase searchvector & return false.
10071  If not any of above, store element in searchvector, set the new current element values from the
10072  SearchElement, then go back to the while loop for the next step in the search.
10073 */
10074 {
10075  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchForPrefDir," + CurrentTrackElement.LogTrack(13) + "," +
10076  AnsiString(XLinkPos) + "," + AnsiString(RequiredPosition));
10077  int VectorCount = 0;
10078 
10079  while(true)
10080  {
10081  if(CurrentTrackElement.Config[XLinkPos] == End) // buffers or continuation
10082  {
10083  for(int x = 0; x < VectorCount; x++)
10084  SearchVector.erase(SearchVector.end() - 1);
10085  Utilities->CallLogPop(141);
10086  return false;
10087  }
10088  int NextPosition = CurrentTrackElement.Conn[XLinkPos];
10089  TTrackElement NextTrackElement = Track->TrackElementAt(74, NextPosition);
10090  TPrefDirElement SearchElement(NextTrackElement);
10091  SearchElement.TrackVectorPosition = NextPosition;
10092  int NextELinkPos = CurrentTrackElement.ConnLinkPos[XLinkPos];
10093  SearchElement.ELinkPos = NextELinkPos;
10094  SearchElement.ELink = SearchElement.Link[SearchElement.ELinkPos];
10095  int NextXLinkPos;
10096  if(SearchElement.ELinkPos == 0)
10097  NextXLinkPos = 1;
10098  if(SearchElement.ELinkPos == 1)
10099  NextXLinkPos = 0;
10100  if(SearchElement.ELinkPos == 2)
10101  NextXLinkPos = 3;
10102  if(SearchElement.ELinkPos == 3)
10103  NextXLinkPos = 2;
10104  if((SearchElement.TrackType != Points) || (SearchElement.Config[SearchElement.ELinkPos] != Lead))
10105  {
10106  SearchElement.XLink = SearchElement.Link[NextXLinkPos];
10107  // but may be buffers, continuation or gap
10108  SearchElement.XLinkPos = NextXLinkPos;
10109  }
10110 // can't set XLink or XLinkPos yet if the element is a leading point.
10111 // check if found it
10112  if(SearchElement.TrackVectorPosition == RequiredPosition)
10113  {
10114  SearchVector.push_back(SearchElement); // XLink & XLinkPos won't be set if a leading point
10115  VectorCount++; // not really needed but include for tidyness
10116  TotalSearchCount++;
10117  Utilities->CallLogPop(142);
10118  return true;
10119  }
10120 // check if PrefDirVector > 200 and if so reject further searches (to avoid possible problems in converting
10121 // very long vectors) - warning given in ConvertPrefDirSearchVector, though can still add elements one
10122 // at a time - drop this
10123 /*
10124  if(PrefDirVector.size() > 200)
10125  {
10126  for(int x=0;x<VectorCount;x++) SearchVector.erase(SearchVector.end() - 1);
10127  Utilities->CallLogPop(1419);
10128  return false;
10129  }
10130 */
10131 // check if a buffer or continuation
10132  if((SearchElement.TrackType == Buffers) || (SearchElement.TrackType == Continuation))
10133  {
10134  for(int x = 0; x < VectorCount; x++)
10135  SearchVector.erase(SearchVector.end() - 1);
10136  Utilities->CallLogPop(143);
10137  return false;
10138  }
10139 // check if reached an earlier position on search PrefDir with same entry value
10140  for(unsigned int x = 0; x < SearchVector.size(); x++)
10141  {
10142  if((SearchElement.TrackVectorPosition == SearchVector.at(x).TrackVectorPosition) && (SearchElement.ELink == SearchVector.at(x).ELink))
10143  {
10144  for(int x = 0; x < VectorCount; x++)
10145  SearchVector.erase(SearchVector.end() - 1);
10146  Utilities->CallLogPop(144);
10147  return false;
10148  }
10149  }
10150 // check if reached an earlier position in the PrefDirVector with same entry value (without this can keep adding entries
10151 // to PrefDir4MultiMap, and since only 4 are searched an error can occur)
10152  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
10153  {
10154  if((SearchElement.TrackVectorPosition == PrefDirVector.at(x).TrackVectorPosition) && (SearchElement.ELink == PrefDirVector.at(x).ELink))
10155  {
10156  for(int x = 0; x < VectorCount; x++)
10157  SearchVector.erase(SearchVector.end() - 1);
10158  Utilities->CallLogPop(1417);
10159  return false;
10160  }
10161  }
10162 
10163 // check if exceeds the search H & V limits - drop in favour of limiting TotalSearchCount
10164 // if((SearchElement.HLoc > SearchLimitHighH) || (SearchElement.HLoc < SearchLimitLowH) ||
10165 // (SearchElement.VLoc > SearchLimitHighV) ||(SearchElement.VLoc < SearchLimitLowV))
10167  {
10168  for(int x = 0; x < VectorCount; x++)
10169  SearchVector.erase(SearchVector.end() - 1);
10170  Utilities->CallLogPop(1691);
10171  return false;
10172  }
10173 
10174 // check if SearchVector reached 150, and if so reject, to save time in searching for PrefDirs
10175  if(SearchVector.size() > 150)
10176  {
10177  for(int x = 0; x < VectorCount; x++)
10178  SearchVector.erase(SearchVector.end() - 1);
10179  Utilities->CallLogPop(1418);
10180  return false;
10181  }
10182 // check if reached a leading point
10183  if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Lead))
10184  {
10185 // push element with XLink set to position [1]
10186  SearchElement.XLink = SearchElement.Link[1];
10187  SearchElement.XLinkPos = 1;
10188  SearchVector.push_back(SearchElement);
10189  VectorCount++;
10190  TotalSearchCount++;
10191  // recursive search at XLinkPos of 1 (i.e. 1st trailing exit)
10192  // Note that have to use a TTrackElement in the recursive search, so SearchElement
10193  // can't be used. NextTrackElement is the corresponding TTrackElement.
10194  if(SearchForPrefDir(8, NextTrackElement, 1, RequiredPosition))
10195  {
10196  Utilities->CallLogPop(145);
10197  return true;
10198  }
10199  else
10200  {
10201 // remove leading point with XLinkPos [1]
10202  SearchVector.erase(SearchVector.end() - 1);
10203  VectorCount--;
10204 // push element with XLink set to position [3]
10205  SearchElement.XLink = SearchElement.Link[3];
10206  SearchElement.XLinkPos = 3;
10207  SearchVector.push_back(SearchElement);
10208  VectorCount++;
10209  TotalSearchCount++;
10210 // recursive search at XLinkPos of 3 (i.e. 2nd trailing exit)
10211  if(SearchForPrefDir(9, NextTrackElement, 3, RequiredPosition))
10212  {
10213  Utilities->CallLogPop(146);
10214  return true;
10215  }
10216  else
10217  {
10218  for(int x = 0; x < VectorCount; x++)
10219  SearchVector.erase(SearchVector.end() - 1);
10220  Utilities->CallLogPop(147);
10221  return false;
10222  }
10223  }
10224  } // if leading point
10225 // here if ordinary element, push it, inc vector & update CurrentTrackElement
10226 // ready for next element on PrefDir
10227  SearchVector.push_back(SearchElement);
10228  VectorCount++;
10229  TotalSearchCount++;
10230  XLinkPos = NextXLinkPos;
10231  CurrentTrackElement = SearchElement;
10232  } // while(true)
10233 }
10234 
10235 // ---------------------------------------------------------------------------
10236 
10238 /*
10239  Enter with SearchVector established. This contains ELink + Pos, XLink + Pos, & TrackVectorPosition
10240  for each element on the search PrefDir, though if the last element is a leading point
10241  then the final XLink won't be set.
10242  Note also that the last element in the PrefDirVector (as opposed to the searchvector) may not have its ELink set (if it was the start)
10243  nor its XLink set (if it was the start or a leading point), so these are checked first and together with EXNumber set as necessary.
10244  The remaining PrefDirVector elements are then set from the searchvector & checkcount keeps pace as values are added.
10245 */
10246 {
10247  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConvertPrefDirSearchVector");
10248  if(SearchVector.size() == 0)
10249  {
10250  throw Exception("Error, SearchVector empty");
10251  }
10252 // get first SearchElement in order to set last PrefDirelement
10253  TPrefDirElement SearchElement = SearchVector.at(0);
10254 
10255 // set last PrefDir element XLink & ELink values if not already set
10256 // ELink & XLink not set if was first element in PrefDir; XLink also not set if was a leading point
10257  for(int x = 0; x < 4; x++)
10258  {
10259  if(PrefDirVector.at(LastElementNumber(42)).Conn[x] == SearchElement.TrackVectorPosition)
10260  {
10261  if(PrefDirVector.at(LastElementNumber(43)).XLink == -1) // i.e. not set
10262  {
10263  PrefDirVector.at(LastElementNumber(44)).XLink = PrefDirVector.at(LastElementNumber(45)).Link[x];
10264  PrefDirVector.at(LastElementNumber(46)).XLinkPos = x;
10265  PrefDirVector.at(LastElementNumber(47)).CheckCount++;
10266  PrefDirVector.at(LastElementNumber(48)).CheckCount++;
10267  }
10268  int ELinkPos;
10269  if(PrefDirVector.at(LastElementNumber(49)).XLinkPos == 0)
10270  ELinkPos = 1; // use actual value rather than 'x' as may be a gap
10271  // with both ends linked to 1st searchvector element, & if XLink was set then x may not correspond
10272  if(PrefDirVector.at(LastElementNumber(50)).XLinkPos == 1)
10273  ELinkPos = 0;
10274  if(PrefDirVector.at(LastElementNumber(51)).XLinkPos == 2)
10275  ELinkPos = 3;
10276  if(PrefDirVector.at(LastElementNumber(52)).XLinkPos == 3)
10277  ELinkPos = 2;
10278  if(PrefDirVector.at(LastElementNumber(53)).ELink == -1) // because was start element
10279  {
10280  PrefDirVector.at(LastElementNumber(54)).ELink = PrefDirVector.at(LastElementNumber(55)).Link[ELinkPos];
10281  PrefDirVector.at(LastElementNumber(56)).ELinkPos = ELinkPos;
10282  PrefDirVector.at(LastElementNumber(57)).CheckCount++;
10283  PrefDirVector.at(LastElementNumber(58)).CheckCount++;
10284  }
10285  break; // no point going any further
10286  }
10287  }
10288 // set EXNumber for last PrefDir element, unless already set
10289 // won't be set if was first element or a leading point
10290  if(PrefDirVector.at(LastElementNumber(59)).EXNumber == -1)
10291  {
10292 /* The order for entries & exits is as follows (1st no = entry, 2nd = exit):-
10293  int EXArray[32][2] = {
10294  {4,6},{2,8}, //horizontal & vertical
10295  {2,4},{6,2},{8,6},{4,8}, //sharp curves
10296  {1,6},{3,8},{9,4},{7,2},{1,8},{3,4},{9,2},{7,6}, //loose curves
10297  {1,9},{3,7} //forward & reverse diagonals
10298 */
10299 
10300  if(!(PrefDirVector.at(LastElementNumber(60)).EntryExitNumber()))
10301  {
10302  throw Exception("Error in EntryExitNumber 1");
10303  }
10304 
10305  PrefDirVector.at(LastElementNumber(61)).EXGraphicPtr = PrefDirVector.at(LastElementNumber(62)).GetPrefDirGraphicPtr();
10306  PrefDirVector.at(LastElementNumber(63)).EntryDirectionGraphicPtr = PrefDirVector.at(LastElementNumber(64)).GetDirectionPrefDirGraphicPtr();
10307  PrefDirVector.at(LastElementNumber(65)).CheckCount++;
10308  }
10309 // Last PrefDir element now complete
10310 
10311 // construct remaining PrefDir elements from searchvector
10312  for(unsigned int x = 0; x < SearchVector.size(); x++)
10313  {
10314  SearchElement = SearchVector.at(x);
10315  TPrefDirElement PrefDirElement(Track->TrackElementAt(75, SearchElement.TrackVectorPosition));
10316  PrefDirElement.TrackVectorPosition = SearchElement.TrackVectorPosition;
10317  PrefDirElement.ELink = SearchElement.ELink;
10318  PrefDirElement.ELinkPos = SearchElement.ELinkPos;
10319  PrefDirElement.XLink = SearchElement.XLink;
10320  PrefDirElement.XLinkPos = SearchElement.XLinkPos;
10321 // if XLink & XLinkPos not set don't account for them in CheckCount
10322  if(PrefDirElement.XLink == -1)
10323  PrefDirElement.CheckCount = 6; // Hloc, VLoc, SpeedTag, ELink, ELinkPos,
10324  // & TrackVectorPosition
10325  else
10326  PrefDirElement.CheckCount = 8; // Hloc, VLoc, SpeedTag, ELink, ELinkPos,
10327  // XLink, XLinkPos, TrackVectorPosition
10328 
10329 // set EXNumber (can't set EXNumber if XLink not set - if finished on a leading point
10330  if(PrefDirElement.XLink != -1)
10331  {
10332  if(!(PrefDirElement.EntryExitNumber()))
10333  {
10334  throw Exception("Error in EntryExitNumber 2");
10335  }
10336  PrefDirElement.EXGraphicPtr = PrefDirElement.GetPrefDirGraphicPtr();
10337  PrefDirElement.EntryDirectionGraphicPtr = PrefDirElement.GetDirectionPrefDirGraphicPtr();
10338  PrefDirElement.CheckCount++;
10339  // all values now incorporated if not a leading point
10340  }
10341 // store PrefDir element
10342  StorePrefDirElement(2, PrefDirElement);
10343  }
10344 // Can now validate if PrefDir finished, i.e. if buffers or continuation, else validate when 'AddPrefDir' button pressed
10345  if((LastElementPtr(0)->TrackType == Buffers) || (LastElementPtr(1)->TrackType == Continuation))
10346  {
10347  if(ValidatePrefDir(2))
10348  {;
10349  } // error messages given within function
10350  }
10352 /* drop this, check dropped from search
10353  if(PrefDirVector.size() > 200)
10354  {
10355  ShowMessage("The selected track segment is becoming too long, until it is accepted further elements can only be added one at a time");
10356  }
10357 */
10358  Utilities->CallLogPop(148);
10359 }
10360 
10361 // ---------------------------------------------------------------------------
10362 
10363 bool TOnePrefDir::EndPossible(int Caller, bool &LeadingPoints)
10364 /*
10365  Return true if selected element is valid as a PrefDir end element, i.e. isn't leading points,
10366  and PrefDir isn't one element long. Used to enable the AddPrefDirButton during PrefDir building.
10367 */
10368 {
10369  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EndPossible");
10370  LeadingPoints = false;
10371  if(PrefDirVector.empty())
10372  {
10373  Utilities->CallLogPop(1786);
10374  return false; // should never be empty but allow for it for safety
10375  }
10376  if(PrefDirVector.size() == 1)
10377  {
10378  Utilities->CallLogPop(149);
10379  return false; // can't end if only one element
10380  }
10381 /*
10382  if((PrefDirVector.at(LastElementNumber()).TrackType != Points) &&
10383  (PrefDirVector.at(LastElementNumber()).TrackType != Crossover))
10384  {
10385  Utilities->CallLogPop(150);
10386  return true;
10387  }
10388 */
10389 // allow for anything but leading points
10390  if((PrefDirVector.at(LastElementNumber(66)).TrackType != Points) || (PrefDirVector.at(LastElementNumber(67)).ELinkPos == 1) ||
10391  (PrefDirVector.at(LastElementNumber(71)).ELinkPos == 3))
10392  {
10393  Utilities->CallLogPop(1776);
10394  return true;
10395  }
10396  else
10397  {
10398  LeadingPoints = true;
10399  Utilities->CallLogPop(151);
10400  return false;
10401  }
10402 }
10403 
10404 // ---------------------------------------------------------------------------
10405 
10407 /*
10408  Checks that all elements in PrefDirVector have been properly set, i.e. don't have their default values,
10409  and that every element is connected to the next element
10410 */
10411 {
10412  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ValidatePrefDir");
10413  int Position;
10414  AnsiString ErrorString;
10415  bool Error = false;
10416 
10417  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
10418  {
10419  if(PrefDirVector.at(x).HLoc == -2000000000)
10420  {
10421  Error = true;
10422  ErrorString = "HLoc";
10423  Position = x;
10424  }
10425  if(PrefDirVector.at(x).VLoc == -2000000000)
10426  {
10427  Error = true;
10428  ErrorString = "VLoc";
10429  Position = x;
10430  }
10431  if(PrefDirVector.at(x).ELink == -1)
10432  {
10433  Error = true;
10434  ErrorString = "ELink";
10435  Position = x;
10436  }
10437  if(PrefDirVector.at(x).ELinkPos == -1)
10438  {
10439  Error = true;
10440  ErrorString = "ELinkPos";
10441  Position = x;
10442  }
10443  if(PrefDirVector.at(x).XLink == -1)
10444  {
10445  Error = true;
10446  ErrorString = "XLink";
10447  Position = x;
10448  }
10449  if(PrefDirVector.at(x).XLinkPos == -1)
10450  {
10451  Error = true;
10452  ErrorString = "XLinkPos";
10453  Position = x;
10454  }
10455  if(PrefDirVector.at(x).SpeedTag == 0)
10456  {
10457  Error = true;
10458  ErrorString = "Tag";
10459  Position = x;
10460  }
10461  if(PrefDirVector.at(x).TrackVectorPosition == -1)
10462  {
10463  Error = true;
10464  ErrorString = "TrackVectorPosition";
10465  Position = x;
10466  }
10467  if(PrefDirVector.at(x).EXNumber == -1)
10468  {
10469  Error = true;
10470  ErrorString = "EXNumber";
10471  Position = x;
10472  }
10473  if(PrefDirVector.at(x).CheckCount != 9)
10474  // HLoc, VLoc, SpeedTag, TrackVectorPosition, ELink, ELinkPos, XLink, XLinkPos & EXNumber
10475  {
10476  Error = true;
10477  ErrorString = "CheckCount";
10478  Position = x;
10479  }
10480 // extra checks
10481  if(PrefDirVector.at(x).EXGraphicPtr == 0)
10482  {
10483  Error = true;
10484  ErrorString = "EntryGraphicPtr";
10485  Position = x;
10486  }
10487  if(PrefDirVector.at(x).EntryDirectionGraphicPtr == 0)
10488  {
10489  Error = true;
10490  ErrorString = "EntryDirectionGraphicPtr";
10491  Position = x;
10492  }
10493 // end of extra checks
10494  if(x > 0)
10495  {
10496  if(PrefDirVector.at(x - 1).Conn[PrefDirVector.at(x - 1).XLinkPos] != PrefDirVector.at(x).TrackVectorPosition)
10497  {
10498  Error = true;
10499  ErrorString = "Last XLink not connected to this element";
10500  Position = x;
10501  }
10502  }
10503  }
10504  if(Error)
10505  {
10506  throw Exception("Error at " + AnsiString(Position) + " " + ErrorString);
10507  }
10508  else
10509  {
10510  Utilities->CallLogPop(153);
10511  return true;
10512  }
10513 }
10514 
10515 // ---------------------------------------------------------------------------
10516 
10517 bool TOnePrefDir::GetPrefDirTruncateElement(int Caller, int HLoc, int VLoc)
10518 /*
10519  This is only called during PrefDir build or distance setting. It truncates at & including the first element in the PrefDir vector
10520  that matches H & V. After the truncate the final element of the remaining PrefDir has its data members reset
10521  to the same defaults as would be the case if the PrefDir had been built up to that point - i.e. for first element
10522  or a leading point.
10523 */
10524 {
10525  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetPrefDirTruncateElement," + AnsiString(HLoc) + "," + AnsiString(VLoc));
10526  for(unsigned int x = 0; x < (PrefDirVector.size()); x++)
10527  {
10528  if((PrefDirVector.at(x).HLoc == HLoc) && (PrefDirVector.at(x).VLoc == VLoc))
10529  {
10530  for(int PrefDirVecPos = (PrefDirVector.size() - 1); PrefDirVecPos >= (int)x; PrefDirVecPos--) // has to be int or will underflow at x==0
10531  {
10532  ErasePrefDirElementAt(1, PrefDirVecPos);
10533  }
10534  if(PrefDirVector.size() == 0)
10535  {
10536  Utilities->CallLogPop(154);
10537  return true;
10538  }
10539  if(PrefDirVector.size() == 1)
10540  {
10541  PrefDirVector.at(x - 1).ELinkPos = -1;
10542  PrefDirVector.at(x - 1).ELink = -1;
10543  PrefDirVector.at(x - 1).XLinkPos = -1;
10544  PrefDirVector.at(x - 1).XLink = -1;
10545  PrefDirVector.at(x - 1).EXNumber = -1;
10546  PrefDirVector.at(x - 1).EXGraphicPtr = 0;
10547  PrefDirVector.at(x - 1).EntryDirectionGraphicPtr = 0;
10548  PrefDirVector.at(x - 1).CheckCount = PrefDirVector.at(x - 1).CheckCount - 5;
10549  Utilities->CallLogPop(155);
10550  return true;
10551  }
10552  // here with truncate element not first element, so ELink & ELinkPos set
10553  // unset XLink & Pos if a leading point
10554  if(PrefDirVector.at(x - 1).Config[PrefDirVector.at(x - 1).ELinkPos] == Lead)
10555  {
10556  PrefDirVector.at(x - 1).XLinkPos = -1;
10557  PrefDirVector.at(x - 1).XLink = -1;
10558  PrefDirVector.at(x - 1).EXNumber = -1;
10559  PrefDirVector.at(x - 1).EXGraphicPtr = 0;
10560  PrefDirVector.at(x - 1).EntryDirectionGraphicPtr = 0;
10561  PrefDirVector.at(x - 1).CheckCount = PrefDirVector.at(x - 1).CheckCount - 3;
10562  Utilities->CallLogPop(156);
10563  return true;
10564  }
10565  Utilities->CallLogPop(157);
10566  return true;
10567  }
10568  }
10569  Utilities->CallLogPop(158);
10570  return false;
10571 }
10572 
10573 // ---------------------------------------------------------------------------
10574 
10575 void TOnePrefDir::PrefDirMarker(int Caller, TPrefDirRoute PrefDirRoute, bool BuildingPrefDir, TDisplay *Disp)
10576  const // PrefDirRoute = PrefDircall or routecall for PrefDir or route; true for BuildingPrefDir
10577 /*
10578  PrefDir and route track marker, including direction markers. Function used for both PrefDirs (PrefDirRoute == PrefDirCall) and routes
10579  (PrefDirRoute == RouteCall). The graphics for marker colours and direction are already stored in all PrefDirElements in
10580  TOnePrefDir and TOneRoute, and this function is called to display them, all in the case of a PrefDir, but for a route only the
10581  first and last elements have direction markers. No markers are displayed if a train is present on an element. Also no
10582  display if EXGraphicPtr not set. If building a PrefDir (BuildingPrefDir true) then the start and end rectangles are also
10583  displayed.
10584 */
10585 {
10586  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PrefDirMarker," + AnsiString(PrefDirRoute) + "," +
10587  AnsiString((short)BuildingPrefDir));
10588  int HPos, VPos;
10589 
10590  if(PrefDirSize() == 0)
10591  {
10592  Utilities->CallLogPop(159);
10593  return;
10594  }
10595  for(unsigned int x = 0; x < PrefDirSize(); x++)
10596  {
10597  TPrefDirElement TempPrefDirElement = PrefDirVector.at(x);
10598 // if(Track->TrackElementAt(76, TempPrefDirElement.TrackVectorPosition).TrainIDOnElement > -1) continue;
10599 // don't plot route element if train present - dropped above as train departing only replotted the part of the route
10600 // that the train was on. Ensure though that whenever plot a route replot trains after else route will overwrite train
10601  // without the above, if route replotted in ClearandRebuildRailway when train is straddling 3 elements
10602  // and before the next train update, then the route element corresponding to the LagElement will be plotted,
10603  // only the front half of which will be overplotted by the back of the train, then when the train is
10604  // updated the route image will remain plotted and stay on screen until a later ClearandRebuildRailway
10605  if(TempPrefDirElement.EXGraphicPtr != 0) // Note: will be 0 if first element or last as leading point
10606  {
10607  Disp->PlotOutput(12, (TempPrefDirElement.HLoc * 16), (TempPrefDirElement.VLoc * 16), TempPrefDirElement.EXGraphicPtr);
10608  if((TempPrefDirElement.EntryDirectionGraphicPtr != 0) && (PrefDirRoute == PrefDirCall)) // PrefDir
10609  {
10610  Disp->PlotOutput(13, (TempPrefDirElement.HLoc * 16), (TempPrefDirElement.VLoc * 16), TempPrefDirElement.EntryDirectionGraphicPtr);
10611  }
10612  else if((TempPrefDirElement.EntryDirectionGraphicPtr != 0) && (PrefDirRoute == RouteCall) && PrefDirSize() > 1)
10613  // Route, no direction if a single element
10614  {
10615  if(x == 0)
10616  {
10617  Disp->PlotOutput(14, (TempPrefDirElement.HLoc * 16), (TempPrefDirElement.VLoc * 16), TempPrefDirElement.EntryDirectionGraphicPtr);
10618  }
10619  if(x == (PrefDirSize() - 1))
10620  {
10621  Disp->PlotOutput(15, (TempPrefDirElement.HLoc * 16), (TempPrefDirElement.VLoc * 16), TempPrefDirElement.EntryDirectionGraphicPtr);
10622  }
10623  }
10624  }
10625  }
10626 
10627 // set start & end element colours if building a PrefDir
10628  if((PrefDirRoute == PrefDirCall) && BuildingPrefDir)
10629  {
10630  HPos = GetFixedPrefDirElementAt(4, 0).HLoc * 16;
10631  VPos = GetFixedPrefDirElementAt(5, 0).VLoc * 16;
10632  Disp->Rectangle(1, HPos, VPos, clB0G0R5, 2, 2); // medium red rectangle
10633  // set last element colour
10634  if(PrefDirSize() > 1)
10635  {
10636  unsigned int LatestPos = PrefDirSize() - 1;
10637  HPos = GetFixedPrefDirElementAt(6, LatestPos).HLoc * 16;
10638  VPos = GetFixedPrefDirElementAt(7, LatestPos).VLoc * 16;
10639  Disp->Rectangle(2, HPos, VPos, clB5G0R0, 4, 2); // smaller blue rectangle
10640  }
10641  }
10642  Disp->Update();
10643  Utilities->CallLogPop(160);
10644 }
10645 
10646 // ---------------------------------------------------------------------------
10647 
10649 /*
10650  Similar to PrefDirMarker but used only to mark EveryPrefDir - red for unidirectional PrefDir & green for bidirectional
10651  Colours taken from the route colours. Plot red first so green overwrites for bidirectional points.
10652 */
10653 {
10654  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EveryPrefDirMarker");
10655  if(PrefDirSize() == 0)
10656  {
10657  Utilities->CallLogPop(1547);
10658  return;
10659  }
10660 
10661  int H, V, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
10662  bool FoundFlag;
10664  TPrefDirElement PrefDirElement0, PrefDirElement1, PrefDirElement2, PrefDirElement3;
10665 
10666  while(MMIT != PrefDir4MultiMap.end())
10667  {
10668  H = MMIT->first.first;
10669  V = MMIT->first.second;
10670  GetVectorPositionsFromPrefDir4MultiMap(6, H, V, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
10671  // always found in order, any missing have PrefDirPosx == -1
10672  if(PrefDirPos0 > -1)
10673  PrefDirElement0 = GetFixedPrefDirElementAt(170, PrefDirPos0); // PrefDirPos0 should always be > -1 but leave as a precaution
10674  if(PrefDirPos1 > -1)
10675  PrefDirElement1 = GetFixedPrefDirElementAt(171, PrefDirPos1);
10676  if(PrefDirPos2 > -1)
10677  PrefDirElement2 = GetFixedPrefDirElementAt(172, PrefDirPos2);
10678  if(PrefDirPos3 > -1)
10679  PrefDirElement3 = GetFixedPrefDirElementAt(173, PrefDirPos3);
10680  if(PrefDirPos3 > -1) // 4 found, mark all PrefDirs bidirectional (operator == ensures no duplicates in ConsolidatePrefDirs)
10681  { // need to plot all 4 in order to obtain all the direction graphics
10682  Disp->PlotOutput(77, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
10683  Disp->PlotOutput(78, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
10684  Disp->PlotOutput(79, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
10685  Disp->PlotOutput(80, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
10686  Disp->PlotOutput(81, (H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
10687  Disp->PlotOutput(82, (H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
10688  Disp->PlotOutput(83, (H * 16), (V * 16), PrefDirElement3.GetRouteGraphicPtr(false, true)); // green
10689  Disp->PlotOutput(84, (H * 16), (V * 16), PrefDirElement3.GetDirectionRouteGraphicPtr(false, true)); // green
10690  MMIT++;
10691  MMIT++;
10692  MMIT++;
10693  MMIT++;
10694  }
10695  else if(PrefDirPos2 > -1) // 3 found, one PrefDir bidirectional & other unidirectional
10696  {
10697  if(PrefDirElement0.EXNumber == PrefDirElement1.EXNumber)
10698  { // 0 & 1 constitute the bidirectional PrefDir
10699  Disp->PlotOutput(89, (H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, false)); // red
10700  Disp->PlotOutput(90, (H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, false)); // red
10701  Disp->PlotOutput(85, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
10702  Disp->PlotOutput(86, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
10703  Disp->PlotOutput(87, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
10704  Disp->PlotOutput(88, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
10705  MMIT++;
10706  MMIT++;
10707  MMIT++;
10708  }
10709  else if(PrefDirElement0.EXNumber == PrefDirElement2.EXNumber)
10710  { // 0 & 2 constitute the bidirectional PrefDir
10711  Disp->PlotOutput(95, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, false)); // red
10712  Disp->PlotOutput(96, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, false)); // red
10713  Disp->PlotOutput(91, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
10714  Disp->PlotOutput(92, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
10715  Disp->PlotOutput(93, (H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
10716  Disp->PlotOutput(94, (H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
10717  MMIT++;
10718  MMIT++;
10719  MMIT++;
10720  }
10721  else
10722  { // 1 & 2 constitute the bidirectional PrefDir
10723  Disp->PlotOutput(101, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
10724  Disp->PlotOutput(102, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
10725  Disp->PlotOutput(97, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
10726  Disp->PlotOutput(98, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
10727  Disp->PlotOutput(99, (H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
10728  Disp->PlotOutput(100, (H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
10729  MMIT++;
10730  MMIT++;
10731  MMIT++;
10732  }
10733  }
10734  else if(PrefDirPos1 > -1) // 2 found, either 1 bidirectional or 2 unidirectional
10735  {
10736  if(PrefDirElement0.EXNumber == PrefDirElement1.EXNumber)
10737  { // 0 & 1 constitute the bidirectional PrefDir
10738  Disp->PlotOutput(103, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
10739  Disp->PlotOutput(104, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
10740  Disp->PlotOutput(105, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
10741  Disp->PlotOutput(106, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
10742  MMIT++;
10743  MMIT++;
10744  }
10745  else
10746  { // 2 unidirectional PrefDirs
10747  Disp->PlotOutput(107, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
10748  Disp->PlotOutput(108, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
10749  Disp->PlotOutput(109, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, false)); // red
10750  Disp->PlotOutput(110, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, false)); // red
10751  MMIT++;
10752  MMIT++;
10753  }
10754  }
10755  else if(PrefDirPos0 > -1) // 1 found, must be unidirectional
10756  {
10757  Disp->PlotOutput(111, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
10758  Disp->PlotOutput(112, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
10759  MMIT++;
10760  }
10761  }
10762  Disp->Update();
10763  Utilities->CallLogPop(1548);
10764 }
10765 
10766 // ---------------------------------------------------------------------------
10767 
10768 void TOnePrefDir::LoadOldPrefDir(int Caller, std::ifstream &VecFile)
10769 {
10770  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadOldPrefDir");
10771  int TempInt;
10772 
10773  ClearPrefDir();
10774  int NumberOfPrefDirElements = 0;
10775 
10776  NumberOfPrefDirElements = Utilities->LoadFileInt(VecFile);
10777  for(int x = 0; x < NumberOfPrefDirElements; x++)
10778  {
10779  VecFile >> TempInt; // TrackVectorPosition
10780  TPrefDirElement LoadPrefDirElement(Track->TrackElementAt(714, TempInt));
10781  LoadPrefDirElement.TrackVectorPosition = TempInt;
10782  VecFile >> TempInt;
10783  LoadPrefDirElement.ELink = TempInt;
10784  VecFile >> TempInt;
10785  LoadPrefDirElement.ELinkPos = TempInt;
10786  VecFile >> TempInt;
10787  LoadPrefDirElement.XLink = TempInt;
10788  VecFile >> TempInt;
10789  LoadPrefDirElement.XLinkPos = TempInt;
10790  VecFile >> TempInt;
10791  LoadPrefDirElement.EXNumber = TempInt;
10792  VecFile >> TempInt;
10793  LoadPrefDirElement.CheckCount = TempInt;
10794  LoadPrefDirElement.IsARoute = Utilities->LoadFileBool(VecFile);
10795  LoadPrefDirElement.AutoSignals = Utilities->LoadFileBool(VecFile);
10796  LoadPrefDirElement.ConsecSignals = Utilities->LoadFileBool(VecFile);
10797  if(!(LoadPrefDirElement.IsARoute))
10798  {
10799  LoadPrefDirElement.EXGraphicPtr = LoadPrefDirElement.GetPrefDirGraphicPtr();
10800  LoadPrefDirElement.EntryDirectionGraphicPtr = LoadPrefDirElement.GetDirectionPrefDirGraphicPtr();
10801  }
10802  else
10803  {
10804  LoadPrefDirElement.EXGraphicPtr = LoadPrefDirElement.GetRouteGraphicPtr(LoadPrefDirElement.AutoSignals, LoadPrefDirElement.ConsecSignals);
10805  LoadPrefDirElement.EntryDirectionGraphicPtr = LoadPrefDirElement.GetDirectionRouteGraphicPtr(LoadPrefDirElement.AutoSignals,
10806  LoadPrefDirElement.ConsecSignals);
10807  }
10808  StorePrefDirElement(5, LoadPrefDirElement);
10809  Utilities->LoadFileString(VecFile); // marker
10810  }
10812  Utilities->CallLogPop(161);
10813 }
10814 
10815 // ---------------------------------------------------------------------------
10816 
10817 void TOnePrefDir::LoadPrefDir(int Caller, std::ifstream &VecFile)
10818 {
10819  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadPrefDir");
10820  int TempInt;
10821 
10822  ClearPrefDir();
10823  int NumberOfPrefDirElements = 0;
10824 
10825  NumberOfPrefDirElements = Utilities->LoadFileInt(VecFile);
10826  for(int x = 0; x < NumberOfPrefDirElements; x++)
10827  {
10828  VecFile >> TempInt; // PrefDirVectorPosition, not used in load
10829  VecFile >> TempInt; // TrackVectorPosition
10830  TPrefDirElement LoadPrefDirElement(Track->TrackElementAt(781, TempInt));
10831  LoadPrefDirElement.TrackVectorPosition = TempInt;
10832  VecFile >> TempInt;
10833  LoadPrefDirElement.ELink = TempInt;
10834  VecFile >> TempInt;
10835  LoadPrefDirElement.ELinkPos = TempInt;
10836  VecFile >> TempInt;
10837  LoadPrefDirElement.XLink = TempInt;
10838  VecFile >> TempInt;
10839  LoadPrefDirElement.XLinkPos = TempInt;
10840  VecFile >> TempInt;
10841  LoadPrefDirElement.EXNumber = TempInt;
10842  VecFile >> TempInt;
10843  LoadPrefDirElement.CheckCount = TempInt;
10844  LoadPrefDirElement.IsARoute = Utilities->LoadFileBool(VecFile);
10845  LoadPrefDirElement.AutoSignals = Utilities->LoadFileBool(VecFile);
10846  LoadPrefDirElement.ConsecSignals = Utilities->LoadFileBool(VecFile);
10847  if(!(LoadPrefDirElement.IsARoute))
10848  {
10849  LoadPrefDirElement.EXGraphicPtr = LoadPrefDirElement.GetPrefDirGraphicPtr();
10850  LoadPrefDirElement.EntryDirectionGraphicPtr = LoadPrefDirElement.GetDirectionPrefDirGraphicPtr();
10851  }
10852  else
10853  {
10854  LoadPrefDirElement.EXGraphicPtr = LoadPrefDirElement.GetRouteGraphicPtr(LoadPrefDirElement.AutoSignals, LoadPrefDirElement.ConsecSignals);
10855  LoadPrefDirElement.EntryDirectionGraphicPtr = LoadPrefDirElement.GetDirectionRouteGraphicPtr(LoadPrefDirElement.AutoSignals,
10856  LoadPrefDirElement.ConsecSignals);
10857  }
10858  StorePrefDirElement(0, LoadPrefDirElement);
10859  AnsiString MarkerString = Utilities->LoadFileString(VecFile); // marker
10860  }
10862  Utilities->CallLogPop(1509);
10863 }
10864 
10865 // ---------------------------------------------------------------------------
10866 
10867 bool TOnePrefDir::CheckOnePrefDir(int Caller, int NumberOfActiveElements, std::ifstream &VecFile) // returns false if no more PrefDirs to check
10868 /*
10869  Called before PrefDir loading as part of the FileIntegrityCheck function, in case there is an error in the
10870  file. Very similar to LoadPrefDir but with value checks instead of storage in PrefDirVector.
10871 */
10872 {
10873  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckOnePrefDir");
10874  int TempInt;
10875  int NumberOfPrefDirElements = 0;
10876 
10877  NumberOfPrefDirElements = Utilities->LoadFileInt(VecFile);
10878  if((NumberOfPrefDirElements < 0) || (NumberOfPrefDirElements > 1000000))
10879  {
10880  Utilities->CallLogPop(1152);
10881  return false;
10882  }
10883  for(int x = 0; x < NumberOfPrefDirElements; x++)
10884  {
10885  if(!Utilities->CheckFileInt(VecFile, x, x)) // vector number
10886  {
10887  Utilities->CallLogPop(1766);
10888  return false;
10889  }
10890  VecFile >> TempInt;
10891  if((TempInt < 0) || (TempInt >= NumberOfActiveElements)) // TrackVectorPosition
10892  {
10893  Utilities->CallLogPop(163);
10894  return false;
10895  }
10896  VecFile >> TempInt;
10897  if((TempInt < -1) || (TempInt > 9)) // ELink
10898  {
10899  Utilities->CallLogPop(162);
10900  return false;
10901  }
10902  VecFile >> TempInt;
10903  if((TempInt < -1) || (TempInt > 3)) // ELinkPos
10904  {
10905  Utilities->CallLogPop(164);
10906  return false;
10907  }
10908  VecFile >> TempInt;
10909  if((TempInt < -1) || (TempInt > 9)) // XLink
10910  {
10911  Utilities->CallLogPop(165);
10912  return false;
10913  }
10914  VecFile >> TempInt;
10915  if((TempInt < -1) || (TempInt > 3)) // XLinkPos
10916  {
10917  Utilities->CallLogPop(166);
10918  return false;
10919  }
10920  VecFile >> TempInt;
10921  if((TempInt < -1) || (TempInt > 27)) // EXNumber
10922  {
10923  Utilities->CallLogPop(167);
10924  return false;
10925  }
10926  VecFile >> TempInt;
10927  if(TempInt != 9) // CheckCount - reduced to 11 after NextPrefDirElement dropped &
10928  // to 9 after End & Stop dropped. Leaving HLoc, VLoc, SpeedTag, TrackVectorPosition, ELink,
10929  // ELinkPos, XLink, XLinkPos & EXNumber
10930  {
10931  Utilities->CallLogPop(168);
10932  return false;
10933  }
10934  VecFile >> TempInt;
10935  if((TempInt != 0) && (TempInt != 1)) // RouteElement
10936  {
10937  Utilities->CallLogPop(1147);
10938  return false;
10939  }
10940  VecFile >> TempInt;
10941  if((TempInt != 0) && (TempInt != 1)) // AutoSignals
10942  {
10943  Utilities->CallLogPop(1510);
10944  return false;
10945  }
10946  VecFile >> TempInt;
10947  if((TempInt != 0) && (TempInt != 1)) // ConsecSignals
10948  {
10949  Utilities->CallLogPop(1148);
10950  return false;
10951  }
10952  if(!Utilities->CheckFileStringZeroDelimiter(VecFile)) // marker
10953  {
10954  Utilities->CallLogPop(1700);
10955  return false;
10956  }
10957  }
10958  Utilities->CallLogPop(169);
10959  return true;
10960 }
10961 
10962 // ---------------------------------------------------------------------------
10963 
10964 void TOnePrefDir::SavePrefDirVector(int Caller, std::ofstream &VecFile)
10965 {
10966  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SavePrefDir");
10967  int NumberOfPrefDirElements = PrefDirVector.size();
10968 
10969  Utilities->SaveFileInt(VecFile, NumberOfPrefDirElements);
10970  for(int y = 0; y < NumberOfPrefDirElements; y++)
10971  {
10972  VecFile << y << '\n'; // extra
10973  VecFile << PrefDirVector.at(y).TrackVectorPosition << '\n';
10974  VecFile << PrefDirVector.at(y).ELink << '\n';
10975  VecFile << PrefDirVector.at(y).ELinkPos << '\n';
10976  VecFile << PrefDirVector.at(y).XLink << '\n';
10977  VecFile << PrefDirVector.at(y).XLinkPos << '\n';
10978  VecFile << PrefDirVector.at(y).EXNumber << '\n';
10979  VecFile << PrefDirVector.at(y).CheckCount << '\n';
10980  Utilities->SaveFileBool(VecFile, PrefDirVector.at(y).IsARoute);
10981  Utilities->SaveFileBool(VecFile, PrefDirVector.at(y).AutoSignals);
10982  Utilities->SaveFileBool(VecFile, PrefDirVector.at(y).ConsecSignals);
10983  if(y == (NumberOfPrefDirElements - 1)) // last element, write a longer delimiter
10984  {
10985  VecFile << "************" << '\0' << '\n'; // marker
10986  }
10987  else
10988  {
10989  VecFile << "******" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
10990  }
10991  }
10992  Utilities->CallLogPop(170);
10993 }
10994 
10995 // ---------------------------------------------------------------------------
10996 
10997 void TOnePrefDir::SaveSearchVector(int Caller, std::ofstream &VecFile)
10998 {
10999  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveSearchVector");
11000  int NumberOfSearchElements = SearchVector.size();
11001 
11002  Utilities->SaveFileInt(VecFile, NumberOfSearchElements);
11003  for(int y = 0; y < NumberOfSearchElements; y++)
11004  {
11005  VecFile << y << '\n'; // extra
11006  VecFile << SearchVector.at(y).TrackVectorPosition << '\n';
11007  VecFile << SearchVector.at(y).ELink << '\n';
11008  VecFile << SearchVector.at(y).ELinkPos << '\n';
11009  VecFile << SearchVector.at(y).XLink << '\n';
11010  VecFile << SearchVector.at(y).XLinkPos << '\n';
11011  VecFile << SearchVector.at(y).EXNumber << '\n';
11012  VecFile << SearchVector.at(y).CheckCount << '\n';
11013  Utilities->SaveFileBool(VecFile, SearchVector.at(y).IsARoute);
11014  Utilities->SaveFileBool(VecFile, SearchVector.at(y).AutoSignals);
11015  Utilities->SaveFileBool(VecFile, SearchVector.at(y).ConsecSignals);
11016  if(y == (NumberOfSearchElements - 1)) // last element, write a longer delimiter
11017  {
11018  VecFile << "************" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
11019  }
11020  else
11021  {
11022  VecFile << "******" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
11023  }
11024  }
11025  Utilities->CallLogPop(1847);
11026 }
11027 
11028 // ---------------------------------------------------------------------------
11029 
11030 void TOnePrefDir::EraseFromPrefDirVectorAnd4MultiMap(int Caller, int HLoc, int VLoc)
11031 /*
11032  Erase element at HLoc and VLoc from the PrefDirVector and from the 4MultiMap. Note that this entails
11033  erasing up to four elements (2 directions and 2 tracks for 4-entry elements).
11034 */
11035 {
11036  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EraseFromPrefDirVectorAnd4MultiMap," + AnsiString(HLoc) + "," +
11037  AnsiString(VLoc));
11038  int VecPos = GetOnePrefDirPosition(1, HLoc, VLoc);
11039 
11040  if(VecPos > -1)
11041  ErasePrefDirElementAt(2, VecPos); // max of 4 to be erased
11042  else
11043  {
11044  Utilities->CallLogPop(171);
11045  return;
11046  }
11047  VecPos = GetOnePrefDirPosition(2, HLoc, VLoc);
11048  if(VecPos > -1)
11049  ErasePrefDirElementAt(3, VecPos);
11050  else
11051  {
11052  Utilities->CallLogPop(172);
11053  return;
11054  }
11055  VecPos = GetOnePrefDirPosition(3, HLoc, VLoc);
11056  if(VecPos > -1)
11057  ErasePrefDirElementAt(4, VecPos);
11058  else
11059  {
11060  Utilities->CallLogPop(173);
11061  return;
11062  }
11063  VecPos = GetOnePrefDirPosition(4, HLoc, VLoc);
11064  if(VecPos > -1)
11065  ErasePrefDirElementAt(5, VecPos);
11066  else
11067  {
11068  Utilities->CallLogPop(174);
11069  return;
11070  }
11071  Utilities->CallLogPop(175);
11072 }
11073 
11074 // ---------------------------------------------------------------------------
11075 /*
11076  void TOnePrefDir::EraseCorruptedElementsAfterTrackBuild()//Delete any PrefDir elements that are no longer valid
11077  //Not needed after new TrackErase (now EraseTrackElement), where blank elements aren't used
11078 
11079  When track is rebuilt any elements that are dispensed with aren't erased immediately, a blank element is put
11080  in their place so that existing linkages will be preserved. At this stage this function is called to remove
11081  any elements in PrefDirVector that correspond directly to blank track elements or that are connected to blank track
11082  elements. Finally the track is reconnected using Track->TryToConnectTrack (if won't connect then returns to
11083  AddTrackStage build mode for corrections to be made) and then EveryPrefDir->RebuildPrefDirVector() called to reset
11084  PrefDirVector to correspond to the new track layout.
11085 
11086  {
11087  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",EraseCorruptedElementsAfterTrackBuild");
11088  if(PrefDirSize() == 0)
11089  {
11090  Utilities->CallLogPop(176);
11091  return;
11092  }
11093  for(int x=(PrefDirVector.size()-1);x>=0;x--)
11094  {
11095  int TV = PrefDirVector.at(x).TrackVectorPosition;
11096  int ConnELink = PrefDirVector.at(x).Conn[PrefDirVector.at(x).ELinkPos];
11097  int ConnXLink = PrefDirVector.at(x).Conn[PrefDirVector.at(x).XLinkPos];
11098  if(Track->BlankElementAt(0, TV))
11099  {
11100  ErasePrefDirElementAt(6, x);
11101  }
11102  //if was a blankelement at x then ConnELink and ConnXLink both -1
11103  else if((ConnELink > -1) && (Track->BlankElementAt(1, ConnELink)))
11104  {
11105  ErasePrefDirElementAt(7, x);
11106  }
11107  //if both ConnELink and ConnXLink correspond to blank elements then OK, element only
11108  //needs to be erased once, but if don't use 'else' then will erase two elements
11109  //since 'x' will correspond to the element after the first erased element
11110  else if((ConnXLink > -1) && (Track->BlankElementAt(2, ConnXLink)))
11111  {
11112  ErasePrefDirElementAt(8, x);
11113  }
11114  }
11115  Utilities->CallLogPop(177);
11116  }
11117 */
11118 // ---------------------------------------------------------------------------
11119 
11120 void TOnePrefDir::ConsolidatePrefDirs(int Caller, TOnePrefDir *InputPrefDir)
11121 /*
11122  This is used to add InputPrefDir's PrefDirVector to TOnePrefDir's PrefDirVector except where it already
11123  exists in TOnePrefDir. In practice it adds ConstructPrefDir to EveryPrefDir.
11124 */
11125 {
11126  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConsolidatePrefDirs");
11127  bool AlreadyPresent, FoundFlag;
11128  int PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
11129 
11130  for(unsigned int x = 0; x < InputPrefDir->PrefDirSize(); x++)
11131  {
11132  TPrefDirElement TempElement = InputPrefDir->PrefDirVector.at(x);
11133  GetVectorPositionsFromPrefDir4MultiMap(1, TempElement.HLoc, TempElement.VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
11134  AlreadyPresent = false;
11135  if(FoundFlag)
11136  {
11137  if((PrefDirPos0 > -1) && (TempElement == GetFixedPrefDirElementAt(8, PrefDirPos0)))
11138  AlreadyPresent = true;
11139  if((PrefDirPos1 > -1) && (TempElement == GetFixedPrefDirElementAt(9, PrefDirPos1)))
11140  AlreadyPresent = true;
11141  if((PrefDirPos2 > -1) && (TempElement == GetFixedPrefDirElementAt(10, PrefDirPos2)))
11142  AlreadyPresent = true;
11143  if((PrefDirPos3 > -1) && (TempElement == GetFixedPrefDirElementAt(11, PrefDirPos3)))
11144  AlreadyPresent = true;
11145  }
11146  if(!AlreadyPresent)
11147  StorePrefDirElement(4, TempElement);
11148  }
11150  Utilities->CallLogPop(178);
11151 }
11152 /* earlier brute force search
11153  for(unsigned int x = 0;x<InputPrefDir->PrefDirSize();x++)
11154  {
11155  TPrefDirElement TempElement = InputPrefDir->GetFixedPrefDirElementAt(12, x);
11156  bool AlreadyPresent = false;
11157  for(unsigned int y = 0;y<PrefDirSize();y++)
11158  {
11159  if(TempElement == GetFixedPrefDirElementAt(13, y)) AlreadyPresent = true;
11160  }
11161  if(!AlreadyPresent) StorePrefDirElement(, TempElement);
11162  }
11163 */
11164 
11165 // ---------------------------------------------------------------------------
11166 
11168 /*
11169  Rebuild from Trackmap, doesn't affect PrefDir4MultiMap.
11170  After a track build, but before the track is reconnected, all invalid PrefDir elements in TOnePrefDir
11171  (i.e. in EveryPrefDir) are erased. Hence at that stage all the PrefDir elements are valid and correspond to
11172  the track elements at relevant H & V positions. However, after the track is reconnected, the TrackVector
11173  positions are likely to have changed, so this function is called to reset all the necessary connections and
11174  TrackVector positions. To be on the safe side all the TrackElement values that are additional to
11175  TFixedTrackPiece (apart from TrainIDs, these only present during operation) are reset, though the others
11176  shouldn't have changed.
11177 */
11178 {
11179  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RebuildPrefDirVector");
11180  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
11181  {
11182  bool FoundFlag;
11183  int VecPos = Track->GetVectorPositionFromTrackMap(10, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc, FoundFlag);
11184  if(FoundFlag)
11185  {
11186  PrefDirVector.at(x).TrackVectorPosition = VecPos;
11187  PrefDirVector.at(x).LocationName = Track->TrackElementAt(78, VecPos).LocationName;
11188  PrefDirVector.at(x).ActiveTrackElementName = Track->TrackElementAt(79, VecPos).ActiveTrackElementName;
11189  PrefDirVector.at(x).ElementID = Track->TrackElementAt(80, VecPos).ElementID;
11190  PrefDirVector.at(x).Attribute = Track->TrackElementAt(81, VecPos).Attribute;
11191  for(unsigned int z = 0; z < 4; z++)
11192  {
11193  PrefDirVector.at(x).Conn[z] = Track->TrackElementAt(82, VecPos).Conn[z];
11194  PrefDirVector.at(x).ConnLinkPos[z] = Track->TrackElementAt(83, VecPos).ConnLinkPos[z];
11195  }
11196  }
11197  else
11198  {
11199  throw Exception("Error in RebuildPrefDirVector - PrefDirVector is unsafe");
11200  }
11201  }
11202  Utilities->CallLogPop(179);
11203 }
11204 
11205 // ---------------------------------------------------------------------------
11206 
11208 /*
11209  Check loaded PrefDir against loaded track, and if discrepancies found give message & clear EveryPrefDir & PrefDir4MultiMap.
11210 */
11211 {
11212  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckPrefDirAgainstTrackVector");
11213  bool DiscrepancyFound = false;
11214 
11215  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
11216  {
11217  bool FoundFlag;
11218  int VecPos = Track->GetVectorPositionFromTrackMap(39, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc, FoundFlag);
11219  if(FoundFlag)
11220  {
11221  TPrefDirElement PE = PrefDirVector.at(x);
11222  if(PE.TrackVectorPosition != VecPos)
11223  DiscrepancyFound = true;
11224  if((PE.GetELinkPos() < 0) || (PE.GetELinkPos() > 3))
11225  {
11226  DiscrepancyFound = true;
11227  break;
11228  }
11229  if((PE.GetXLinkPos() < 0) || (PE.GetXLinkPos() > 3))
11230  {
11231  DiscrepancyFound = true;
11232  break;
11233  }
11234  if(PE.ELink != Track->TrackElementAt(710, VecPos).Link[PE.GetELinkPos()])
11235  {
11236  DiscrepancyFound = true;
11237  break;
11238  }
11239  if(PE.XLink != Track->TrackElementAt(711, VecPos).Link[PE.GetXLinkPos()])
11240  {
11241  DiscrepancyFound = true;
11242  break;
11243  }
11244  }
11245  else
11246  DiscrepancyFound = true;
11247  }
11248  if(DiscrepancyFound)
11249  {
11250  ShowMessage("Discrepancies found in the preferred direction file, preferred directions will be cleared");
11251  ClearPrefDir(); // also clears multimap
11252  }
11253  Utilities->CallLogPop(1436);
11254 }
11255 
11256 // ---------------------------------------------------------------------------
11257 
11259 /*
11260  Check loaded PrefDir against loaded track, and if discrepancies found clear EveryPrefDir & PrefDir4MultiMap.
11261  return true for OK
11262 */
11263 {
11264  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckPrefDirAgainstTrackVectorNoMessage");
11265  bool DiscrepancyFound = false;
11266 
11267  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
11268  {
11269  bool FoundFlag;
11270  int VecPos = Track->GetVectorPositionFromTrackMap(36, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc, FoundFlag);
11271  if(FoundFlag)
11272  {
11273  TPrefDirElement PE = PrefDirVector.at(x);
11274  if(PE.TrackVectorPosition != VecPos)
11275  DiscrepancyFound = true;
11276  if((PE.GetELinkPos() < 0) || (PE.GetELinkPos() > 3))
11277  {
11278  DiscrepancyFound = true;
11279  break;
11280  }
11281  if((PE.GetXLinkPos() < 0) || (PE.GetXLinkPos() > 3))
11282  {
11283  DiscrepancyFound = true;
11284  break;
11285  }
11286  if(PE.ELink != Track->TrackElementAt(715, VecPos).Link[PE.GetELinkPos()])
11287  {
11288  DiscrepancyFound = true;
11289  break;
11290  }
11291  if(PE.XLink != Track->TrackElementAt(716, VecPos).Link[PE.GetXLinkPos()])
11292  {
11293  DiscrepancyFound = true;
11294  break;
11295  }
11296  }
11297  else
11298  DiscrepancyFound = true;
11299  }
11300  Utilities->CallLogPop(1512);
11301  return !DiscrepancyFound;
11302 }
11303 
11304 // ---------------------------------------------------------------------------
11305 
11306 void TOnePrefDir::CheckPrefDir4MultiMap(int Caller) // test
11307 /*
11308  Test function to check correspondence between PrefDirVector and PrefDir4MultiMap for each element in
11309  turn and for the overall sizes.
11310 */
11311 {
11312  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckPrefDir4MultiMap");
11313  bool FoundFlag = false;
11314  int PrefDir0, PrefDir1, PrefDir2, PrefDir3;
11315 
11316  for(unsigned int a = 0; a < PrefDirVector.size(); a++)
11317  {
11318  TPrefDirElement CheckElement = PrefDirVector.at(a);
11319  GetVectorPositionsFromPrefDir4MultiMap(2, CheckElement.HLoc, CheckElement.VLoc, FoundFlag, PrefDir0, PrefDir1, PrefDir2, PrefDir3);
11320  if(!FoundFlag)
11321  {
11322  throw Exception("CheckPrefDir4MultiMap Error - failed to find HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" + (AnsiString)CheckElement.VLoc +
11323  " in PrefDir4MultiMap, Caller=" + (AnsiString)Caller);
11324  }
11325  if((PrefDir0 != (int)a) && (PrefDir1 != (int)a) && (PrefDir2 != (int)a) && (PrefDir3 != (int)a))
11326  {
11327  throw Exception("CheckPrefDir4MultiMap Error - MapVectorPosition failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
11328  (AnsiString)CheckElement.VLoc + " Map values=" + (AnsiString)PrefDir0 + ", " + (AnsiString)PrefDir1 + ", " + (AnsiString)PrefDir2 + ", " +
11329  (AnsiString)PrefDir3 + " PrefDirVectorPos value=" + (AnsiString)a + " Caller=" + (AnsiString)Caller);
11330  }
11331  }
11332  if(PrefDirVector.size() != PrefDir4MultiMap.size())
11333  {
11334  throw Exception("CheckPrefDir4MultiMap Error - Map Size=" + (AnsiString)PrefDirVector.size() + " PrefDirVectorSize=" + (AnsiString)PrefDirVector.size()
11335  + " Caller=" + (AnsiString)Caller);
11336  }
11337  Utilities->CallLogPop(180);
11338 }
11339 
11340 // ---------------------------------------------------------------------------
11341 
11342 void TOnePrefDir::GetVectorPositionsFromPrefDir4MultiMap(int Caller, int HLoc, int VLoc, bool &FoundFlag, int &PrefDirPos0, int &PrefDirPos1, int &PrefDirPos2,
11343  int &PrefDirPos3)
11344 /*
11345  There are up to four elements at each H & V position in the PrefDirVector - two directions, and up to
11346  two tracks for 4-entry elements. This function retrieves all elements that are present at a give H & V
11347  position. FoundFlag indicates whether any or none have been found, and PrefDirPos0, 1, 2 & 3 contain
11348  the PrefDirVector positions, or -1 if not present. The elements are always found in order, such that
11349  if there is only one it will be in PrefDirPos0, if two they will be in PrefDirPos0 and PrefDirPos1 and so on.
11350 */
11351 {
11352  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetVectorPositionsFromPrefDir4MultiMap," + AnsiString(HLoc) + "," +
11353  AnsiString(VLoc));
11354  THVPair PrefDirMapKeyPair;
11355 
11356  PrefDirPos0 = -1;
11357  PrefDirPos1 = -1;
11358  PrefDirPos2 = -1;
11359  PrefDirPos3 = -1;
11360  FoundFlag = false;
11361  PrefDirMapKeyPair.first = HLoc;
11362  PrefDirMapKeyPair.second = VLoc;
11363  std::pair<TPrefDir4MultiMapIterator, TPrefDir4MultiMapIterator>ItPair;
11364 
11365  ItPair = PrefDir4MultiMap.equal_range(PrefDirMapKeyPair);
11366  if(ItPair.first == ItPair.second)
11367  {
11368  Utilities->CallLogPop(181);
11369  return;
11370  }
11371  else
11372  {
11373  FoundFlag = true;
11374  PrefDirPos0 = ItPair.first->second;
11375  ItPair.first++;
11376  if(ItPair.first == ItPair.second)
11377  {
11378  Utilities->CallLogPop(182);
11379  return;
11380  }
11381  if(((ItPair.first->first).first == HLoc) && ((ItPair.first->first).second == VLoc))
11382  PrefDirPos1 = ItPair.first->second;
11383  ItPair.first++;
11384  if(ItPair.first == ItPair.second)
11385  {
11386  Utilities->CallLogPop(183);
11387  return;
11388  }
11389  if(((ItPair.first->first).first == HLoc) && ((ItPair.first->first).second == VLoc))
11390  PrefDirPos2 = ItPair.first->second;
11391  ItPair.first++;
11392  if(ItPair.first == ItPair.second)
11393  {
11394  Utilities->CallLogPop(184);
11395  return;
11396  }
11397  if(((ItPair.first->first).first == HLoc) && ((ItPair.first->first).second == VLoc))
11398  PrefDirPos3 = ItPair.first->second;
11399  }
11400  Utilities->CallLogPop(185);
11401 }
11402 
11403 // ---------------------------------------------------------------------------
11404 
11405 void TOnePrefDir::StorePrefDirElement(int Caller, TPrefDirElement LoadPrefDirElement)
11406 /*
11407  LoadPrefDirElement is stored in both the PrefDirVector and in PrefDir4MultiMap.
11408 */
11409 {
11410  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",StorePrefDirElement," + LoadPrefDirElement.LogPrefDir());
11411  PrefDirVector.push_back(LoadPrefDirElement);
11412  THVPair PrefDir4MultiMapKeyPair;
11413  TPrefDir4MultiMapEntry PrefDir4MultiMapEntry;
11414 
11415  PrefDir4MultiMapKeyPair.first = LoadPrefDirElement.HLoc;
11416  PrefDir4MultiMapKeyPair.second = LoadPrefDirElement.VLoc;
11417  PrefDir4MultiMapEntry.first = PrefDir4MultiMapKeyPair;
11418  PrefDir4MultiMapEntry.second = LastElementNumber(68);
11419  PrefDir4MultiMap.insert(PrefDir4MultiMapEntry);
11420 // CheckPrefDir4MultiMap(1);Drop here as takes too long - call it by each calling function
11421  Utilities->CallLogPop(186);
11422 }
11423 
11424 // ---------------------------------------------------------------------------
11425 
11426 void TOnePrefDir::ErasePrefDirElementAt(int Caller, int PrefDirVectorPosition)
11427 /*
11428  Erase a single element from PrefDirVector and 4MultiMap, decrementing the remaining PrefDirElementNumbers in
11429  4MultiMap if they are greater than the erased value.
11430 */
11431 {
11432  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ErasePrefDirElementAt," + AnsiString(PrefDirVectorPosition));
11433  bool FoundFlag;
11434 
11435  if(!PrefDirVector.empty())
11436  {
11437  TPrefDir4MultiMapIterator EraseIt = GetExactMatchFrom4MultiMap(0, PrefDirVectorPosition, FoundFlag);
11438  if(!FoundFlag)
11439  {
11440  throw Exception("Failed to find PrefDir4MultiMap erase element");
11441  }
11442  PrefDirVector.erase(PrefDirVector.begin() + PrefDirVectorPosition);
11443  PrefDir4MultiMap.erase(EraseIt);
11444  DecrementPrefDirElementNumbersInPrefDir4MultiMap(0, PrefDirVectorPosition);
11446  }
11447  Utilities->CallLogPop(187);
11448 }
11449 
11450 // ---------------------------------------------------------------------------
11451 
11452 void TOnePrefDir::DecrementPrefDirElementNumbersInPrefDir4MultiMap(int Caller, unsigned int ErasedElementNumber)
11453 /*
11454  Called after ErasePrefDirElementAt(int PrefDirVectorPosition) to decrement the remaining PrefDirElementNumbers in
11455  4MultiMap if they are greater than the erased value.
11456 */
11457 {
11458  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementPrefDirElementNumbersInPrefDir4MultiMap," +
11459  AnsiString(ErasedElementNumber));
11460  if(!PrefDir4MultiMap.empty())
11461  {
11462  for(TPrefDir4MultiMapIterator MapPtr = PrefDir4MultiMap.begin(); MapPtr != PrefDir4MultiMap.end(); MapPtr++)
11463  {
11464  if(MapPtr->second > ErasedElementNumber)
11465  MapPtr->second--;
11466  }
11467  }
11468  Utilities->CallLogPop(1450);
11469 }
11470 
11471 // ---------------------------------------------------------------------------
11472 
11473 TOnePrefDir::TPrefDir4MultiMapIterator TOnePrefDir::GetExactMatchFrom4MultiMap(int Caller, unsigned int PrefDirVectorPosition, bool &FoundFlag)
11474 /*
11475  Retrieves a PrefDir4MultiMap iterator to the PrefDir element at PrefDirVectorPosition. Used during
11476  ErasePrefDirElementAt(int PrefDirVectorPosition) to erase the relevant element in the multimap. If
11477  nothing is found this is an error but the error message is given in the calling function.
11478 */
11479 {
11480  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetExactMatchFrom4MultiMap," + AnsiString(PrefDirVectorPosition));
11481  FoundFlag = false;
11482  if(PrefDirVectorPosition >= PrefDirVector.size())
11483  {
11484  throw Exception("PrefDirVectorPosition out of range");
11485  }
11486  TPrefDirElement PrefDirElement = GetFixedPrefDirElementAt(14, PrefDirVectorPosition);
11487  THVPair PrefDir4MultiMapKeyPair;
11488 
11489  PrefDir4MultiMapKeyPair.first = PrefDirElement.HLoc;
11490  PrefDir4MultiMapKeyPair.second = PrefDirElement.VLoc;
11491  std::pair<TPrefDir4MultiMapIterator, TPrefDir4MultiMapIterator>ItPair;
11492 
11493  ItPair = PrefDir4MultiMap.equal_range(PrefDir4MultiMapKeyPair);
11494  if(ItPair.first == ItPair.second)
11495  {
11496  Utilities->CallLogPop(188);
11497  return ItPair.first; // nothing found but have to return an iterator, FoundFlag indicates nothing found
11498  }
11499  else
11500  {
11501  if(ItPair.first->second == PrefDirVectorPosition)
11502  {
11503  FoundFlag = true;
11504  Utilities->CallLogPop(189);
11505  return ItPair.first;
11506  }
11507  ItPair.first++;
11508  if(ItPair.first == ItPair.second)
11509  {
11510  Utilities->CallLogPop(190);
11511  return ItPair.first; // nothing found
11512  }
11513  if(ItPair.first->second == PrefDirVectorPosition)
11514  {
11515  FoundFlag = true;
11516  Utilities->CallLogPop(191);
11517  return ItPair.first;
11518  }
11519  ItPair.first++;
11520  if(ItPair.first == ItPair.second)
11521  {
11522  Utilities->CallLogPop(192);
11523  return ItPair.first; // nothing found
11524  }
11525  if(ItPair.first->second == PrefDirVectorPosition)
11526  {
11527  FoundFlag = true;
11528  Utilities->CallLogPop(193);
11529  return ItPair.first;
11530  }
11531  ItPair.first++;
11532  if(ItPair.first == ItPair.second)
11533  {
11534  Utilities->CallLogPop(194);
11535  return ItPair.first; // nothing found
11536  }
11537  if(ItPair.first->second == PrefDirVectorPosition)
11538  {
11539  FoundFlag = true;
11540  Utilities->CallLogPop(195);
11541  return ItPair.first;
11542  }
11543  }
11544  Utilities->CallLogPop(196);
11545  return ItPair.first; // nothing found
11546 }
11547 
11548 // ---------------------------------------------------------------------------
11549 
11550 int TOnePrefDir::GetOnePrefDirPosition(int Caller, int HLoc, int VLoc)
11551 /*
11552  Although there may be up to four entries at one H & V position this function gets just one. It is
11553  used in EraseFromPrefDirVectorAnd4MultiMap by being called as many times as there are PrefDir elements
11554  at H & V.
11555 */
11556 {
11557  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetOnePrefDirPosition," + AnsiString(HLoc) + "," + AnsiString(VLoc));
11558  THVPair PrefDir4MultiMapKeyPair;
11559 
11560  PrefDir4MultiMapKeyPair.first = HLoc;
11561  PrefDir4MultiMapKeyPair.second = VLoc;
11562  std::pair<TPrefDir4MultiMapIterator, TPrefDir4MultiMapIterator>ItPair;
11563 
11564  ItPair = PrefDir4MultiMap.equal_range(PrefDir4MultiMapKeyPair);
11565  if(ItPair.first == ItPair.second) // nothing found
11566  {
11567  Utilities->CallLogPop(197);
11568  return -1;
11569  }
11570  else
11571  {
11572  Utilities->CallLogPop(198);
11573  return ItPair.first->second;
11574  }
11575 }
11576 
11577 // ---------------------------------------------------------------------------
11578 
11579 void TOnePrefDir::RealignAfterTrackErase(int Caller, int ErasedTrackVectorPosition)
11580 {
11581  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RealignAfterTrackErase," + AnsiString(ErasedTrackVectorPosition));
11582  bool ErasedFlag = false;
11583 
11584  if(ErasedTrackVectorPosition > -1) // should be in calling function but include here as a safeguard
11585  {
11586  if(PrefDirSize() == 0)
11587  {
11588  Utilities->CallLogPop(1511);
11589  return;
11590  }
11591  for(int x = (PrefDirSize() - 1); x >= 0; x--) // reverse because of erase
11592  {
11593  ErasedFlag = false;
11594  // use 'else' to ensure don't try to access an erased element
11595  if(PrefDirVector.at(x).TrackVectorPosition == ErasedTrackVectorPosition)
11596  {
11597  ErasePrefDirElementAt(11, x);
11598  ErasedFlag = true;
11599  }
11600  else if(PrefDirVector.at(x).Conn[0] == ErasedTrackVectorPosition)
11601  {
11602  ErasePrefDirElementAt(12, x);
11603  ErasedFlag = true;
11604  }
11605  else if(PrefDirVector.at(x).Conn[1] == ErasedTrackVectorPosition)
11606  {
11607  ErasePrefDirElementAt(13, x);
11608  ErasedFlag = true;
11609  }
11610  else if(PrefDirVector.at(x).Conn[2] == ErasedTrackVectorPosition)
11611  {
11612  ErasePrefDirElementAt(9, x);
11613  ErasedFlag = true;
11614  }
11615  else if(PrefDirVector.at(x).Conn[3] == ErasedTrackVectorPosition)
11616  {
11617  ErasePrefDirElementAt(10, x);
11618  ErasedFlag = true;
11619  }
11620  if(!ErasedFlag)
11621  {
11622  // don't use 'else' here as may be more than one that need decrementing
11623  if(PrefDirVector.at(x).TrackVectorPosition > ErasedTrackVectorPosition)
11624  {
11625  PrefDirVector.at(x).TrackVectorPosition--;
11626  }
11627  if(PrefDirVector.at(x).Conn[0] > ErasedTrackVectorPosition)
11628  {
11629  PrefDirVector.at(x).Conn[0]--;
11630  }
11631  if(PrefDirVector.at(x).Conn[1] > ErasedTrackVectorPosition)
11632  {
11633  PrefDirVector.at(x).Conn[1]--;
11634  }
11635  if(PrefDirVector.at(x).Conn[2] > ErasedTrackVectorPosition)
11636  {
11637  PrefDirVector.at(x).Conn[2]--;
11638  }
11639  if(PrefDirVector.at(x).Conn[3] > ErasedTrackVectorPosition)
11640  {
11641  PrefDirVector.at(x).Conn[3]--;
11642  }
11643  }
11644  }
11645  }
11646  Utilities->CallLogPop(1434);
11647 }
11648 
11649 // ---------------------------------------------------------------------------
11650 
11651 void TOnePrefDir::CalcDistanceAndSpeed(int Caller, int &OverallDistance, int &OverallSpeedLimit, bool &LeadingPointsAtLastElement)
11652 {
11653  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CalcDistanceAndSpeed");
11654  OverallDistance = 0;
11655  OverallSpeedLimit = 0;
11656  LeadingPointsAtLastElement = false;
11657  if(PrefDirSize() == 0) // shouldn't be empty when this called
11658  {
11659  Utilities->CallLogPop(1491);
11660  return;
11661  }
11662 
11663  if((LastElementPtr(21)->TrackType == Points) && (LastElementPtr(22)->ELinkPos != 1) && (LastElementPtr(23)->ELinkPos != 3))
11664  {
11665  LeadingPointsAtLastElement = true;
11666  Utilities->CallLogPop(1492);
11667  return;
11668  }
11669  for(unsigned int x = 0; x < PrefDirSize(); x++)
11670  {
11671  TPrefDirElement PrefDirElement = GetFixedPrefDirElementAt(166, x);
11672  if((PrefDirElement.GetELinkPos() > 1) || (PrefDirElement.GetXLinkPos() > 1)) // 'or' because points may have one == 0 & other == 3
11673  {
11674  OverallDistance += PrefDirElement.Length23;
11675  if(OverallSpeedLimit != -1) // if set to -1 there are mixed speed limits
11676  {
11677  if(x == 0)
11678  {
11679  OverallSpeedLimit = PrefDirElement.SpeedLimit23;
11680  }
11681  else
11682  {
11683  if(OverallSpeedLimit != PrefDirElement.SpeedLimit23)
11684  {
11685  OverallSpeedLimit = -1;
11686  }
11687  }
11688  }
11689  }
11690  else
11691  {
11692  OverallDistance += PrefDirElement.Length01;
11693  if(OverallSpeedLimit != -1) // if set to -1 there are mixed speed limits
11694  {
11695  if(x == 0)
11696  {
11697  OverallSpeedLimit = PrefDirElement.SpeedLimit01;
11698  }
11699  else
11700  {
11701  if(OverallSpeedLimit != PrefDirElement.SpeedLimit01)
11702  {
11703  OverallSpeedLimit = -1;
11704  }
11705  }
11706  }
11707  }
11708  }
11709  Utilities->CallLogPop(1529);
11710 }
11711 
11712 // ---------------------------------------------------------------------------
11713 
11714 void TOnePrefDir::WritePrefDirToImage(int Caller, Graphics::TBitmap *Bitmap)
11715 {
11716  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WritePrefDirToImage");
11717  if(PrefDirSize() == 0)
11718  {
11719  Utilities->CallLogPop(1564);
11720  return;
11721  }
11722 
11723  int H, V, HLoc, VLoc, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
11724  bool FoundFlag;
11726  TPrefDirElement PrefDirElement0, PrefDirElement1, PrefDirElement2, PrefDirElement3;
11727 
11728  while(MMIT != PrefDir4MultiMap.end())
11729  {
11730  HLoc = MMIT->first.first;
11731  VLoc = MMIT->first.second;
11732  GetVectorPositionsFromPrefDir4MultiMap(7, HLoc, VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
11733  H = HLoc - Track->GetHLocMin();
11734  V = VLoc - Track->GetVLocMin();
11735  // always found in order, any missing have PrefDirPosx == -1
11736  if(PrefDirPos0 > -1)
11737  PrefDirElement0 = GetFixedPrefDirElementAt(174, PrefDirPos0); // PrefDirPos0 should always be > -1 but leave as a precaution
11738  if(PrefDirPos1 > -1)
11739  PrefDirElement1 = GetFixedPrefDirElementAt(175, PrefDirPos1);
11740  if(PrefDirPos2 > -1)
11741  PrefDirElement2 = GetFixedPrefDirElementAt(176, PrefDirPos2);
11742  if(PrefDirPos3 > -1)
11743  PrefDirElement3 = GetFixedPrefDirElementAt(177, PrefDirPos3);
11744  if(PrefDirPos3 > -1) // 4 found, mark all PrefDirs bidirectional (operator == ensures no duplicates in ConsolidatePrefDirs)
11745  { // need to plot all 4 in order to obtain all the direction graphics
11746  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
11747  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
11748  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
11749  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
11750  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
11751  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
11752  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement3.GetRouteGraphicPtr(false, true)); // green
11753  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement3.GetDirectionRouteGraphicPtr(false, true)); // green
11754  MMIT++;
11755  MMIT++;
11756  MMIT++;
11757  MMIT++;
11758  }
11759  else if(PrefDirPos2 > -1) // 3 found, one PrefDir bidirectional & other unidirectional
11760  {
11761  if(PrefDirElement0.EXNumber == PrefDirElement1.EXNumber)
11762  { // 0 & 1 constitute the bidirectional PrefDir
11763  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
11764  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
11765  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
11766  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
11767  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, false)); // red
11768  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, false)); // red
11769  MMIT++;
11770  MMIT++;
11771  MMIT++;
11772  }
11773  else if(PrefDirElement0.EXNumber == PrefDirElement2.EXNumber)
11774  { // 0 & 2 constitute the bidirectional PrefDir
11775  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
11776  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
11777  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
11778  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
11779  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, false)); // red
11780  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, false)); // red
11781  MMIT++;
11782  MMIT++;
11783  MMIT++;
11784  }
11785  else
11786  { // 1 & 2 constitute the bidirectional PrefDir
11787  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
11788  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
11789  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
11790  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
11791  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
11792  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
11793  MMIT++;
11794  MMIT++;
11795  MMIT++;
11796  }
11797  }
11798  else if(PrefDirPos1 > -1) // 2 found, either 1 bidirectional or 2 unidirectional
11799  {
11800  if(PrefDirElement0.EXNumber == PrefDirElement1.EXNumber)
11801  { // 0 & 1 constitute the bidirectional PrefDir
11802  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
11803  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
11804  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
11805  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
11806  MMIT++;
11807  MMIT++;
11808  }
11809  else
11810  { // 2 unidirectional PrefDirs
11811  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
11812  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
11813  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, false)); // red
11814  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, false)); // red
11815  MMIT++;
11816  MMIT++;
11817  }
11818  }
11819  else if(PrefDirPos0 > -1) // 1 found, must be unidirectional
11820  {
11821  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
11822  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
11823  MMIT++;
11824  }
11825  }
11826  Utilities->CallLogPop(1565);
11827 }
11828 
11829 // ---------------------------------------------------------------------------
11830 
11831 bool TOnePrefDir::PresetAutoRouteElementValid(int Caller, TPrefDirElement ElementIn, int EntryPos) // added at v1.2.0
11832 /*
11833  Checks ElementIn and returns true only if a single prefdir set at that H&V, with EntryPos giving entry position, not points, crossovers,
11834  level crossing, signals with wrong direction set, or buffers.
11835 */
11836 {
11837  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PresetAutoRouteElementValid");
11838  int PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
11839  bool FoundFlag;
11841  TPrefDirElement PrefDirElement0, PrefDirElement1, PrefDirElement2, PrefDirElement3;
11842 
11843  if((ElementIn.TrackType == Points) || (ElementIn.TrackType == Crossover) || (ElementIn.TrackType == Buffers) || (Track->IsLCAtHV(49, ElementIn.HLoc,
11844  ElementIn.VLoc)))
11845  {
11846  Utilities->CallLogPop(1982);
11847  return false;
11848  }
11849  if((ElementIn.TrackType == SignalPost) && (ElementIn.Config[EntryPos] == Signal)) // Signal is at exit end
11850  {
11851  Utilities->CallLogPop(1983);
11852  return false;
11853  }
11854  if((ElementIn.TrackType == SignalPost) && (ElementIn.SigAspect == TTrackElement::GroundSignal))
11855  {
11856  Utilities->CallLogPop(1995);
11857  return false;
11858  }
11859 // Now check that there is only a single prefdir set
11860  GetVectorPositionsFromPrefDir4MultiMap(8, ElementIn.HLoc, ElementIn.VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
11861 // always found in order, any missing have PrefDirPosx == -1
11862  if(PrefDirPos0 > -1)
11863  PrefDirElement0 = GetFixedPrefDirElementAt(213, PrefDirPos0); // PrefDirPos0 should always be > -1 but leave as a precaution
11864  if(PrefDirPos1 > -1)
11865  PrefDirElement1 = GetFixedPrefDirElementAt(214, PrefDirPos1);
11866  if(PrefDirPos2 > -1)
11867  PrefDirElement2 = GetFixedPrefDirElementAt(215, PrefDirPos2);
11868  if(PrefDirPos3 > -1)
11869  PrefDirElement3 = GetFixedPrefDirElementAt(216, PrefDirPos3);
11870 
11871  if(PrefDirPos3 > -1) // 4 found, all bidirectional
11872  {
11873  Utilities->CallLogPop(1984);
11874  return false;
11875  }
11876  else if(PrefDirPos2 > -1) // 3 found, one PrefDir bidirectional & other unidirectional
11877  {
11878  if((PrefDirElement0.XLinkPos == EntryPos) || (PrefDirElement1.XLinkPos == EntryPos) || (PrefDirElement2.XLinkPos == EntryPos))
11879  {
11880  Utilities->CallLogPop(1985);
11881  return false;
11882  }
11883  else
11884  {
11885  Utilities->CallLogPop(1986);
11886  return true;
11887  }
11888  }
11889  else if(PrefDirPos1 > -1) // 2 found, either 1 bidirectional or 2 unidirectional
11890  {
11891  if((PrefDirElement0.XLinkPos == EntryPos) || (PrefDirElement1.XLinkPos == EntryPos))
11892  {
11893  Utilities->CallLogPop(1987);
11894  return false;
11895  }
11896  else
11897  {
11898  Utilities->CallLogPop(1988);
11899  return true;
11900  }
11901  }
11902  else if(PrefDirPos0 > -1) // one found, make sure in correct direction
11903  {
11904  if(PrefDirElement0.XLinkPos == EntryPos)
11905  {
11906  Utilities->CallLogPop(1989);
11907  return false;
11908  }
11909  else
11910  {
11911  Utilities->CallLogPop(1990);
11912  return true;
11913  }
11914  }
11915  else
11916  {
11917  Utilities->CallLogPop(1991);
11918  return false; // none found
11919  }
11920 }
11921 
11922 // ---------------------------------------------------------------------------
11923 
11925 {
11926 /* //Added at v2.1.0
11927  Called by GetStartAndEndPrefDirElements, which in turn is called by PresetAutoSigRoutesButtonClick. Checks for a diagonal link in
11928  the autosigsroute being fouled by an adjacent track with a corresponding link that meets at the diagonal link, and if it is it
11929  returns true and prevents the route being set. Note that adjacent track consisting of buffers, gaps and continuations at the
11930  diagonal link are also excluded though they need not be, but it makes the check code simpler and such adjacent track is untidy
11931  and can be modelled better anyway.
11932 
11933  Enter with PrefDirElement whose XLink is to be checked for track that fouls a diagonal.
11934  If XLink is anything but 1,3,7 or 9 return false - no fouling as not a diagonal.
11935  for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
11936  for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
11937  for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
11938  for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
11939 */
11940  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PresetAutoRouteDiagonalFouledByTrack," + ElementIn.HLoc + "," +
11941  ElementIn.VLoc + "," + XLink);
11942  int TrackVecPos;
11943  bool TrackFoundFlag;
11944  TTrackElement TempTrackElement;
11945 
11946  if((XLink == 2) || (XLink == 4) || (XLink == 6) || (XLink == 8))
11947  {
11948  Utilities->CallLogPop(2047);
11949  return false;
11950  }
11951 
11952 // for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
11953  if(XLink == 1)
11954  {
11955  TrackVecPos = Track->GetVectorPositionFromTrackMap(48, ElementIn.HLoc - 1, ElementIn.VLoc, TrackFoundFlag);
11956  if(TrackFoundFlag)
11957  {
11958  TempTrackElement = Track->TrackElementAt(898, TrackVecPos);
11959  if((TempTrackElement.Link[0] == 3) || (TempTrackElement.Link[1] == 3) || (TempTrackElement.Link[2] == 3) || (TempTrackElement.Link[3] == 3))
11960  {
11961  Utilities->CallLogPop(2048);
11962  return true;
11963  }
11964  }
11965  TrackVecPos = Track->GetVectorPositionFromTrackMap(49, ElementIn.HLoc, ElementIn.VLoc - 1, TrackFoundFlag);
11966  if(TrackFoundFlag)
11967  {
11968  TempTrackElement = Track->TrackElementAt(899, TrackVecPos);
11969  if((TempTrackElement.Link[0] == 7) || (TempTrackElement.Link[1] == 7) || (TempTrackElement.Link[2] == 7) || (TempTrackElement.Link[3] == 7))
11970  {
11971  Utilities->CallLogPop(2049);
11972  return true;
11973  }
11974  }
11975  }
11976 
11977 // for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
11978  if(XLink == 3)
11979  {
11980  TrackVecPos = Track->GetVectorPositionFromTrackMap(50, ElementIn.HLoc + 1, ElementIn.VLoc, TrackFoundFlag);
11981  if(TrackFoundFlag)
11982  {
11983  TempTrackElement = Track->TrackElementAt(900, TrackVecPos);
11984  if((TempTrackElement.Link[0] == 1) || (TempTrackElement.Link[1] == 1) || (TempTrackElement.Link[2] == 1) || (TempTrackElement.Link[3] == 1))
11985  {
11986  Utilities->CallLogPop(2050);
11987  return true;
11988  }
11989  }
11990  TrackVecPos = Track->GetVectorPositionFromTrackMap(51, ElementIn.HLoc, ElementIn.VLoc - 1, TrackFoundFlag);
11991  if(TrackFoundFlag)
11992  {
11993  TempTrackElement = Track->TrackElementAt(901, TrackVecPos);
11994  if((TempTrackElement.Link[0] == 9) || (TempTrackElement.Link[1] == 9) || (TempTrackElement.Link[2] == 9) || (TempTrackElement.Link[3] == 9))
11995  {
11996  Utilities->CallLogPop(2051);
11997  return true;
11998  }
11999  }
12000  }
12001 
12002 // for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
12003  if(XLink == 7)
12004  {
12005  TrackVecPos = Track->GetVectorPositionFromTrackMap(52, ElementIn.HLoc - 1, ElementIn.VLoc, TrackFoundFlag);
12006  if(TrackFoundFlag)
12007  {
12008  TempTrackElement = Track->TrackElementAt(902, TrackVecPos);
12009  if((TempTrackElement.Link[0] == 9) || (TempTrackElement.Link[1] == 9) || (TempTrackElement.Link[2] == 9) || (TempTrackElement.Link[3] == 9))
12010  {
12011  Utilities->CallLogPop(2052);
12012  return true;
12013  }
12014  }
12015  TrackVecPos = Track->GetVectorPositionFromTrackMap(53, ElementIn.HLoc, ElementIn.VLoc + 1, TrackFoundFlag);
12016  if(TrackFoundFlag)
12017  {
12018  TempTrackElement = Track->TrackElementAt(903, TrackVecPos);
12019  if((TempTrackElement.Link[0] == 1) || (TempTrackElement.Link[1] == 1) || (TempTrackElement.Link[2] == 1) || (TempTrackElement.Link[3] == 1))
12020  {
12021  Utilities->CallLogPop(2053);
12022  return true;
12023  }
12024  }
12025  }
12026 
12027 // for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
12028  if(XLink == 9)
12029  {
12030  TrackVecPos = Track->GetVectorPositionFromTrackMap(54, ElementIn.HLoc + 1, ElementIn.VLoc, TrackFoundFlag);
12031  if(TrackFoundFlag)
12032  {
12033  TempTrackElement = Track->TrackElementAt(904, TrackVecPos);
12034  if((TempTrackElement.Link[0] == 7) || (TempTrackElement.Link[1] == 7) || (TempTrackElement.Link[2] == 7) || (TempTrackElement.Link[3] == 7))
12035  {
12036  Utilities->CallLogPop(2054);
12037  return true;
12038  }
12039  }
12040  TrackVecPos = Track->GetVectorPositionFromTrackMap(55, ElementIn.HLoc, ElementIn.VLoc + 1, TrackFoundFlag);
12041  if(TrackFoundFlag)
12042  {
12043  TempTrackElement = Track->TrackElementAt(905, TrackVecPos);
12044  if((TempTrackElement.Link[0] == 3) || (TempTrackElement.Link[1] == 3) || (TempTrackElement.Link[2] == 3) || (TempTrackElement.Link[3] == 3))
12045  {
12046  Utilities->CallLogPop(2055);
12047  return true;
12048  }
12049  }
12050  }
12051  Utilities->CallLogPop(2056);
12052  return false;
12053 }
12054 
12055 // ---------------------------------------------------------------------------
12056 
12057 bool TOnePrefDir::GetStartAndEndPrefDirElements(int Caller, TPrefDirElement &StartElement, TPrefDirElement &EndElement, int &LastIteratorValue)
12058 {
12059 /* Called by PresetAutoSigRoutesButtonClick in the Interface unit. LastIteratorValue gives the position in EveryPrefDir to start from. Search
12060  EveryPrefDir for continuations (facing inwards wrt pref dir) or non-ground signals in single direction pref dirs, and when find one track forwards
12061  to the next non-ground signal or continuation. If, before finding a valid signal or continuation find points, crossover, level crossing or buffers,
12062  or an element that is already in a route, stop tracking and continue with the search for another valid continuation or signal. When find a suitable
12063  pair, return the elements in StartElement and EndElement, and also the LastIteratorValue ready for the next call.
12064 */
12065  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetStartAndEndPrefDirElements," + AnsiString(LastIteratorValue));
12067  bool FoundFlag, ContFlag, FoundElements = false;
12068  int PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
12069  TPrefDirElement NextElement;
12070 
12071  for(PDVIt = (PrefDirVector.begin() + LastIteratorValue); PDVIt < PrefDirVector.end(); PDVIt++)
12072  {
12073  LastIteratorValue++;
12074  ContFlag = false;
12075  if((PDVIt->TrackType != SignalPost) && (PDVIt->TrackType != Continuation))
12076  continue;
12077  if((PDVIt->TrackType == SignalPost) && (PDVIt->SigAspect == TTrackElement::GroundSignal))
12078  continue;
12079 // if(AllRoutes::TrackIsInARoute(, PDVIt->TrackVectorPosition, PDVIt->EntryPos) continue; //already in a route - no, don't check start position as if a signal might well be at end of an existing route
12080  // found a potential route start point
12081  if(PresetAutoRouteDiagonalFouledByTrack(0, *PDVIt, PDVIt->XLink)) // Added at v2.1.0
12082  {
12083  continue;
12084  }
12085  if(PresetAutoRouteElementValid(0, *PDVIt, PDVIt->ELinkPos))
12086  {
12087  // check if continuation either in a route or with prefdir facing 'End' (OK if find it as EndElement, but not as StartElement)
12088  if(PDVIt->TrackType == Continuation)
12089  {
12090  if(AllRoutes->TrackIsInARoute(18, PDVIt->TrackVectorPosition, PDVIt->ELinkPos))
12091  {
12092  continue;
12093  }
12094  if(PDVIt->XLinkPos == 0) // position 0 is the continuation
12095  {
12096  continue;
12097  }
12098  }
12099  StartElement = *PDVIt;
12100 // in Glenn Mitchell's error log (14/04/13) the offending signal start position was 4680, problem was it linked to a point with pref dirs set on through track but signal linked to
12101  // diverging track on which there was no pref dir. See below for 2 required changes.
12102  }
12103  else
12104  {
12105  continue;
12106  }
12107  // now track along until find a signal or continuation, checking validity for each element
12108  int NextTrackVectorPosition = PDVIt->Conn[PDVIt->GetXLinkPos()];
12109  GetVectorPositionsFromPrefDir4MultiMap(9, Track->TrackElementAt(878, NextTrackVectorPosition).HLoc,
12110  Track->TrackElementAt(879, NextTrackVectorPosition).VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
12111  if(PrefDirPos0 == -1) // no continuing prefdir
12112  {
12113  continue;
12114  }
12115  bool NextElementFoundFlag = false;
12116  if(GetFixedPrefDirElementAt(217, PrefDirPos0).ELinkPos == PDVIt->ConnLinkPos[PDVIt->GetXLinkPos()])
12117  {
12118  NextElement = GetFixedPrefDirElementAt(218, PrefDirPos0);
12119  NextElementFoundFlag = true;
12120  }
12121  if(PrefDirPos1 > -1)
12122  {
12123  if(GetFixedPrefDirElementAt(219, PrefDirPos1).ELinkPos == PDVIt->ConnLinkPos[PDVIt->GetXLinkPos()])
12124  {
12125  NextElement = GetFixedPrefDirElementAt(220, PrefDirPos1);
12126  NextElementFoundFlag = true;
12127  }
12128  }
12129  if(PrefDirPos2 > -1)
12130  {
12131  if(GetFixedPrefDirElementAt(221, PrefDirPos2).ELinkPos == PDVIt->ConnLinkPos[PDVIt->GetXLinkPos()])
12132  {
12133  NextElement = GetFixedPrefDirElementAt(222, PrefDirPos2);
12134  NextElementFoundFlag = true;
12135  }
12136  }
12137  if(PrefDirPos3 > -1)
12138  {
12139  if(GetFixedPrefDirElementAt(223, PrefDirPos3).ELinkPos == PDVIt->ConnLinkPos[PDVIt->GetXLinkPos()])
12140  {
12141  NextElement = GetFixedPrefDirElementAt(224, PrefDirPos3);
12142  NextElementFoundFlag = true;
12143  }
12144  }
12145  if(!NextElementFoundFlag)
12146  {
12147  continue; // Modified for release 1.3.2 (sent as beta to John Phillipson initially)
12148 // throw(Exception("Failed to track prefdir in PresetAutoSigRoutesButtonClick (1)")); //[GM error 14/04/13] for next release change this to 'continue;' to quit from trying to find the auto route (don't need to throw an exception)
12149  }
12150  while(true)
12151  {
12152  // check validity
12153  if(PresetAutoRouteDiagonalFouledByTrack(1, NextElement, NextElement.XLink)) // Added at v2.1.0
12154  {
12155  ContFlag = true;
12156  break;
12157  }
12158  if(!PresetAutoRouteElementValid(1, NextElement, NextElement.ELinkPos))
12159  {
12160  ContFlag = true;
12161  break;
12162  }
12163  // check if in a route, providing not a signal, as a signal might be at the start of a route
12164  if(NextElement.TrackType != SignalPost)
12165  {
12166  if(AllRoutes->TrackIsInARoute(17, NextElement.TrackVectorPosition, NextElement.ELinkPos))
12167  {
12168  ContFlag = true;
12169  break;
12170  }
12171  }
12172  if((NextElement.TrackType == SignalPost) || (NextElement.TrackType == Continuation))
12173  // can't be a gound signal as would have failed the validity test
12174  {
12175  EndElement = NextElement;
12176  break;
12177  }
12178  // get the next element in the sequence
12179  NextTrackVectorPosition = NextElement.Conn[NextElement.GetXLinkPos()];
12180  GetVectorPositionsFromPrefDir4MultiMap(10, Track->TrackElementAt(880, NextTrackVectorPosition).HLoc,
12181  Track->TrackElementAt(881, NextTrackVectorPosition).VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
12182  if(PrefDirPos0 == -1) // no continuing prefdir
12183  {
12184  ContFlag = true;
12185  break;
12186  }
12187  if(GetFixedPrefDirElementAt(225, PrefDirPos0).ELinkPos == NextElement.ConnLinkPos[NextElement.GetXLinkPos()])
12188  {
12189  NextElement = GetFixedPrefDirElementAt(226, PrefDirPos0);
12190  continue;
12191  }
12192  if(PrefDirPos1 > -1)
12193  {
12194  if(GetFixedPrefDirElementAt(227, PrefDirPos1).ELinkPos == NextElement.ConnLinkPos[NextElement.GetXLinkPos()])
12195  {
12196  NextElement = GetFixedPrefDirElementAt(228, PrefDirPos1);
12197  continue;
12198  }
12199  }
12200  if(PrefDirPos2 > -1)
12201  {
12202  if(GetFixedPrefDirElementAt(229, PrefDirPos2).ELinkPos == NextElement.ConnLinkPos[NextElement.GetXLinkPos()])
12203  {
12204  NextElement = GetFixedPrefDirElementAt(230, PrefDirPos2);
12205  continue;
12206  }
12207  }
12208  if(PrefDirPos3 > -1)
12209  {
12210  if(GetFixedPrefDirElementAt(231, PrefDirPos3).ELinkPos == NextElement.ConnLinkPos[NextElement.GetXLinkPos()])
12211  {
12212  NextElement = GetFixedPrefDirElementAt(232, PrefDirPos3);
12213  continue;
12214  }
12215  }
12216  // had exception thrown here if NextElement not found, but could be a bridge where opposite track PrefDir set, in which case won't find it
12217  // found with Jonathan Kwok's DLR railway (17/11/12) where undertrack PrefDir not set just west of Poplar. Hence first test if element is a bridge
12218  // and if so set ContFlag to true & break (same as not finding PrefDir element at all). Modified at version 1.3.1
12219  // note that it's not NextElement that is to be examined but NextTrackVectorPosition, which can be found easily by using PrefDirPos0 (there will be a
12220  // PrefDirPos0 or would have exited earlier, and it doesn't matter that PrefDirPos0 isn't on the route in question because only the TrackType is needed)
12221  if(GetFixedPrefDirElementAt(243, PrefDirPos0).TrackType == Bridge)
12222  {
12223  ContFlag = true;
12224  break;
12225  }
12226  else
12227  {
12228  ContFlag = true; // Modified for release 1.3.2 (sent as beta to John Phillipson initially)
12229  // could drop the bridge test but keep it to show the change history
12230  break;
12231 // throw(Exception("Failed to track prefdir in PresetAutoSigRoutesButtonClick (2)")); //[GM error 14/04/13] for next release set ContFlag to true & break' to quit from trying to find the auto route (don't need to throw an exception)
12232  }
12233  }
12234  if(ContFlag)
12235  continue;
12236  // else have start and end elements set & all elements valid, so set up the route segment
12237  FoundElements = true;
12238  break;
12239  }
12240  if(FoundElements)
12241  {
12242  Utilities->CallLogPop(1992);
12243  return true;
12244  }
12245  else
12246  {
12247  Utilities->CallLogPop(1993);
12248  return false;
12249  }
12250 }
12251 
12252 // ---------------------------------------------------------------------------
12253 // TOneRoute
12254 // ---------------------------------------------------------------------------
12255 
12256 bool TOneRoute::GetPreferredRouteStartElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool ConsecSignalsRoute, bool AutoSigsFlag)
12257 {
12258 /* General:
12259  The basis of all these route setting functions, preferred and non-preferred, is that a SearchVector is set up
12260  containing all the new elements to form the route. When complete, the SearchVector is converted into route
12261  elements, either as a new route, or an extension to an existing route. The AutoSigs flag determines whether the
12262  route will use automatic signals or not.
12263  For preferred and non-preferred routes, all new elements (as opposed to those already in existing routes) go
12264  into the SearchVector. For non-preferred routes, trackelements are selected that are not necessarily PrefDir
12265  elements, so additional work is needed to complete all their members before they are ready for conversion into
12266  a route - see SetRemainingSearchVectorValues. The call order is GetStart....; GetNext...,
12267  which includes the Search... function; [SetRemainingSearchVectorValues for non-preferred routes only], then
12268  ConvertAndAdd.......
12269 
12270  Note that originally intended to allow preferred routes without consecutive signals, hence ConsecSignalsRoute flag.
12271  Later decided to enforce ConsecSignalsRoute for preferred routes, but left original code as was.
12272 
12273  Specific:
12274 
12275  Function returns true for a valid start element, false, with a message, if not.
12276  ClearRoute to empty both PrefDirVector & SearchVector
12277  Check selection matches a TrackElement & ensure a signal/buffers/continuation if using ConsecSignals,
12278  else disallow points, bridge or crossover.
12279  Disallow if train on element.
12280 
12281  Set default values for parameters that are retained in AllRoutes:-
12282  StartSelectionRouteID = route that selection starts in or adjacent to end of;
12283  StartRoutePosition = trackvectornumber of the element to be used as the start of the route;
12284  StartElement1 = the 1st or only TPrefDirElement of the route start element
12285  StartElement2 = the 2nd (if exists) TPrefDirElement of the start element (can be a max of 2 PrefDirs for
12286  a given selection that isn't points, bridge or crossover;
12287 
12288  Check selection corresponds to at least 1 PrefDir element in EveryPrefDir & set StartElement1 & possibly also 2. If
12289  signal/buffers/continuation for ConsecSignalsRoute, or buffers/continuation for not ConsecSignalsRoute,
12290  ensure the PrefDir corresponds to the direction of the signal or away from the buffers/continuation.
12291  Check if in an existing route. Disallow if start anywhere except at end of the route, if the route end is an 'End'
12292  configuration (nowhere to go), and if the end of the route links forwards into another route.
12293  If these tests passed set StartSelectionRouteID, StartElement1 and StartRoutePosition to correspond to the route end element
12294  and blank StartElement2 (only want to use the route element), then return true.
12295  Check also that doesn't lie in >1 route & give error message if so - should never happen.
12296  Check if adjacent to start or end of an existing route & disallow.
12297  The start element (with AutoSignals member set as AutoSigs flag) is stored in SearchVector, unless an existing route element is to
12298  be used as the start element.
12299 */
12300  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetPreferredRouteStartElement," + AnsiString(HLoc) + "," +
12301  AnsiString(VLoc) + "," + AnsiString((short)AutoSigsFlag));
12302  ClearRoute();
12303  int TrackVectorPosition;
12304  TTrackElement TrackElement;
12305  TPrefDirElement FirstElement, LastElement;
12306 
12307  if(!(Track->FindNonPlatformMatch(7, HLoc, VLoc, TrackVectorPosition, TrackElement)))
12308  {
12309  Utilities->CallLogPop(199);
12310  return false;
12311  }
12312  if(ConsecSignalsRoute)
12313  {
12314  if(AutoSigsFlag && (TrackElement.TrackType == Buffers)) // added at v1.2.0
12315  {
12316  TrainController->StopTTClockMessage(80, "Can't create an automatic signal route from buffers");
12317  Utilities->CallLogPop(1996);
12318  return false;
12319  }
12320  else if((TrackElement.TrackType != SignalPost) && (TrackElement.TrackType != Buffers) && (TrackElement.TrackType != Continuation))
12321  {
12322  TrainController->StopTTClockMessage(7, "Must select a valid signal, buffers or continuation");
12323  Utilities->CallLogPop(200);
12324  return false;
12325  }
12326  }
12327  else
12328  {
12329  if((TrackElement.TrackType == Points) || (TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Crossover))
12330  {
12331  TrainController->StopTTClockMessage(8, "Can't select points, bridge or crossover when route building");
12332 // makes later adjacent route checks too complicated
12333  Utilities->CallLogPop(201);
12334  return false;
12335  }
12336  }
12337 
12338  if(Track->IsLCAtHV(18, HLoc, VLoc))
12339  {
12340  TrainController->StopTTClockMessage(73, "Can't start a route on a level crossing");
12341  Utilities->CallLogPop(1909);
12342  return false;
12343  }
12344 
12345 // check if selected a train & disallow if so
12346  if(TrackElement.TrainIDOnElement > -1)
12347  {
12348  TrainController->StopTTClockMessage(9, "Can't start a route on a train");
12349  Utilities->CallLogPop(202);
12350  return false;
12351  }
12352 
12353 // check if selected a locked route element & disallow (can only be a 2-track element so only need check XLinkPos values of 0 & 1
12354  TPrefDirElement PrefDirElement;
12355  int LockedVectorNumber;
12356 
12357  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(1, TrackVectorPosition, 0, PrefDirElement, LockedVectorNumber))
12358  {
12359  TrainController->StopTTClockMessage(10, "Can't start a route on a locked route");
12360  Utilities->CallLogPop(203);
12361  return false;
12362  }
12363  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(2, TrackVectorPosition, 1, PrefDirElement, LockedVectorNumber))
12364  {
12365  TrainController->StopTTClockMessage(11, "Can't start a route on a locked route");
12366  Utilities->CallLogPop(204);
12367  return false;
12368  }
12369 
12371  StartRoutePosition = TrackVectorPosition; // actual route start - may be element following StartRouteSelectPosition if select a
12372 // signal in an autosig route & follow with a non-autosig route
12373 
12374  TPrefDirElement BlankElement;
12375 
12376  StartElement1 = BlankElement;
12377  StartElement2 = BlankElement;
12378 // check it's in a PrefDir (could be 2 entries for two possible PrefDirs, can only select single track elements so can't have more than 2 PrefDirs)
12379  bool InPrefDirFlag = false;
12380 
12381  bool FoundFlag;
12382  int PrefDirPos0 = -1;
12383  int PrefDirPos1 = -1;
12384  int PrefDirPos2 = -1;
12385  int PrefDirPos3 = -1;
12386 
12388  Track->TrackElementAt(85, StartRoutePosition).VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
12389  int PrefDirVecPos[4] =
12390  {PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3};
12391 
12392  for(int x = 0; x < 4; x++)
12393  {
12394  int b = PrefDirVecPos[x];
12395  if(b > -1)
12396  {
12397  if(ConsecSignalsRoute)
12398  {
12399  // only allow the appropriate exit route to be searched
12400  if(((TrackElement.TrackType == SignalPost) && (EveryPrefDir->GetFixedPrefDirElementAt(15, b).Config[EveryPrefDir->GetFixedPrefDirElementAt(16,
12401  b).XLinkPos] == Signal)) || ((TrackElement.TrackType == Buffers) && (EveryPrefDir->GetFixedPrefDirElementAt(17,
12402  b).Config[EveryPrefDir->GetFixedPrefDirElementAt(18, b).XLinkPos] == Connection)) ||
12403  ((TrackElement.TrackType == Continuation) && (EveryPrefDir->GetFixedPrefDirElementAt(19,
12404  b).Config[EveryPrefDir->GetFixedPrefDirElementAt(20, b).XLinkPos] == Connection)))
12405  {
12406  InPrefDirFlag = true;
12407  StartElement1 = EveryPrefDir->GetFixedPrefDirElementAt(21, b);
12408  if(AutoSigsFlag)
12409  {
12410  StartElement1.AutoSignals = true;
12411  }
12413  StartElement2 = BlankElement;
12414  }
12415  }
12416  else
12417  {
12418  // only allow the appropriate exit route to be searched
12419  // AutoSignals & ConsecSignals stay false for not ConsecSignalsRoute
12420  if(((TrackElement.TrackType == Buffers) && (EveryPrefDir->GetFixedPrefDirElementAt(22, b).Config[EveryPrefDir->GetFixedPrefDirElementAt(23,
12421  b).XLinkPos] == Connection)) || ((TrackElement.TrackType == Continuation) && (EveryPrefDir->GetFixedPrefDirElementAt(24,
12422  b).Config[EveryPrefDir->GetFixedPrefDirElementAt(25, b).XLinkPos] == Connection)))
12423  {
12424  InPrefDirFlag = true;
12425  StartElement1 = EveryPrefDir->GetFixedPrefDirElementAt(26, b);
12426  StartElement2 = BlankElement;
12427  }
12428  else if((TrackElement.TrackType != Buffers) && (TrackElement.TrackType != Continuation))
12429  {
12430  InPrefDirFlag = true;
12432  StartElement1 = EveryPrefDir->GetFixedPrefDirElementAt(27, b);
12433  else
12434  StartElement2 = EveryPrefDir->GetFixedPrefDirElementAt(28, b);
12435  }
12436  }
12437  }
12438  }
12439 
12440  if(!InPrefDirFlag)
12441  {
12443  "Route and preferred direction mismatch. If no preferred direction then only red routes can be used. Green and blue route directions must correspond to the preferred direction.");
12444  Utilities->CallLogPop(205);
12445  return false;
12446  }
12447 
12448 // look for exact match in a route first - can't be a bridge so can use a simple 'find'
12450  TAllRoutes::TRouteElementPair RoutePair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(14, TrackElement.HLoc, TrackElement.VLoc, DummyPair);
12451 
12452  if(DummyPair.first > -1) // if DummyPair exists then an error as start element can only be in one route (bridges not allowed)
12453  {
12454  throw Exception("Selection in two routes - should never happen!");
12455  }
12456 
12457  if(RoutePair.first > -1) // no need to examine DummyPair as start element can only be in one route (bridges not allowed)
12458  {
12459  if(RoutePair.second != AllRoutes->GetFixedRouteAt(1, RoutePair.first).PrefDirSize() - 1) // not last element in existing route so no good
12460  {
12461  TrainController->StopTTClockMessage(13, "Can't start a route within or at the start of an existing route");
12462  Utilities->CallLogPop(206);
12463  return false;
12464  }
12465  TPrefDirElement RouteElement = AllRoutes->GetFixedRouteAt(2, RoutePair.first).GetFixedPrefDirElementAt(29, RoutePair.second);
12466  if(RouteElement.Conn[RouteElement.XLinkPos] < 0) // last element in existing route but nowhere to go!
12467  {
12468  TrainController->StopTTClockMessage(14, "No forward connection from this position");
12469  Utilities->CallLogPop(207);
12470  return false;
12471  }
12472  if((RouteElement.Config[RouteElement.XLinkPos] != End) && (AllRoutes->TrackIsInARoute(9, RouteElement.Conn[RouteElement.XLinkPos],
12473  RouteElement.ConnLinkPos[RouteElement.XLinkPos])))
12474  // last element in existing route but that route linked to another route (or a non-bridge 2-track element containing a route) so no good
12475  {
12476  TrainController->StopTTClockMessage(15, "Can't start a route at an element that links forward into an existing route");
12477  Utilities->CallLogPop(208);
12478  return false;
12479  }
12480  StartSelectionRouteID = IDInt(AllRoutes->GetFixedRouteAt(158, RoutePair.first).RouteID);
12482  AllRoutes->GetFixedRouteAt(4, RoutePair.first).PrefDirSize() - 1); // last element
12483  if(AutoSigsFlag)
12484  {
12485  StartElement1.AutoSignals = true;
12486  }
12487  if(ConsecSignalsRoute)
12488  {
12490  }
12491  StartElement2 = BlankElement; // only use the route element
12493  Utilities->CallLogPop(209);
12494  return true; // all retained values (StartElement1 & maybe 2; StartRoutePosition) set
12495  }
12496 
12497  else // no route started
12498  {
12499 // check if selected position is adjacent to start or end of an existing route and disallow
12500  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
12501  {
12502  FirstElement = AllRoutes->GetFixedRouteAt(5, a).GetFixedPrefDirElementAt(31, 0);
12503  if((StartElement1.Conn[0] > -1) && (StartElement1.Conn[0] == FirstElement.TrackVectorPosition))
12504  {
12505  TrainController->StopTTClockMessage(16, "Can't make selection adjacent to start of another route");
12506  Utilities->CallLogPop(210);
12507  return false;
12508  }
12509  if((StartElement1.Conn[1] > -1) && (StartElement1.Conn[1] == FirstElement.TrackVectorPosition))
12510  {
12511  TrainController->StopTTClockMessage(17, "Can't make selection adjacent to start of another route");
12512  Utilities->CallLogPop(211);
12513  return false;
12514  }
12515  }
12516 
12517 // check if it's adjacent to end of an an existing route,
12518  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
12519  {
12521  if(LastElement.Conn[LastElement.XLinkPos] == StartRoutePosition)
12522  {
12523  TrainController->StopTTClockMessage(18, "Can't start a route adjacent to the end of an existing route");
12524  Utilities->CallLogPop(212);
12525  return false;
12526  }
12527  }
12528  SearchVector.push_back(StartElement1);
12529  Utilities->CallLogPop(213);
12530  return true;
12531  }
12532 }
12533 
12534 // ---------------------------------------------------------------------------
12535 
12536 bool TOneRoute::GetNextPreferredRouteElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool ConsecSignalsRoute, bool AutoSigsFlag,
12537  IDInt &ReqPosRouteID, bool &PointsChanged)
12538 
12539 /*
12540  [Note this was written when it was intended to have routes confined to preferred direction elements but with a choice of whether
12541  they had to run from signal to signal (bool ConsecSignalsRoute true), or not (bool ConsecSignalsRoute false), as well as using
12542  automatic signals or not. Since then it was decided only to allow these routes to run from signal to signal, so ConsecSignalsRoute
12543  is always true when this routine is called. The routine could be made much simpler, but has been left as is because it works (at
12544  least it has done so far), and it allows the original option to be used if it ever seems appropriate in the future.]
12545  *
12546  Return true if select valid next element, in which case the route is set & stored. Return false for an invalid next element.
12547  *
12548  Declare integers EndPosition (the position used) and
12549  ReqPosRouteID to hold (when required) the existing route selected, this being set to -1 for not used.
12550  Check if selection is a valid track element, cancel if not, if select original start element or if select buffers
12551  with AutoSigsFlag set - would have no way out and no way to cancel the route with a train at the buffers.
12552  Check correct type of element - signal/buffers/continuation if ConsecSignalsRoute, else not points, bridge or crossover.
12553  Fail if train on element, or if selection not in EveryPrefDir. Otherwise set EndElement1 & possibly also
12554  EndElement2 corresponding to the 2 possible PrefDir elements (similar to StartElement1 & 2 above).
12555  Check if selection is first element in an existing route & if so set ReqPosRouteID, EndElement1, and set EndElement2 to
12556  blank as can only be one route at that element (can't select bridges). Fail if in a route & not at start, or at start but route
12557  linked forward to another route.
12558  Check & fail if adjacent to start or end of an existing route, or if select the route that selected at start (though earlier check
12559  for same position as start should cover this)
12560  *
12561  If there's a StartSelectionRouteID then StartElement1 will be set to the last entry in the selected route so use
12562  SearchForPreferredRoute to search for the selected end element from this start element. If succeed then set the search vector
12563  graphics using SetRouteSearchVectorGraphics(AutoSigsFlag) & return true, for Interface to handle the flashing & time delay. After the
12564  delay completes the Interface flasher calls ConvertAndAddPreferredRouteSearchVector to add the new route to the AllRoutesVectorPtr.
12565  If the search fails the return false.
12566  If there isn't a StartSelectionRouteID then the starting element is not already in a route, so it will have been stored
12567  in the SearchVector to ensure it's entered as part of the new route.
12568  First check whether the selected element (either EndElement1 or 2) is adjacent to the starting position and if so set the route to go
12569  directly to it (as opposed to going round a long loop to get to it just because that XLinkPos happens to be chosen first. If not
12570  adjacent then first search on EndElement1, and if fail search on EndElement2 providing it's set. If succeed set
12571  set the search vector graphics as above and return. If reach end of function then have failed to find a valid element,
12572  so return false, with an appropriate message if ConsecSignalsRoute set.
12573 */
12574 
12575 {
12576  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetNextPreferredRouteElement," + AnsiString(HLoc) + "," +
12577  AnsiString(VLoc) + "," + AnsiString((short)AutoSigsFlag));
12578  int EndPosition; // the position selected
12579 
12580  Track->LCFoundInAutoSigsRoute = false;
12582  TotalSearchCount = 0;
12583  ReqPosRouteID = IDInt(-1); // default value for not used
12584  TTrackElement TrackElement;
12585  TPrefDirElement EndElement1, EndElement2, BlankElement; // all blank to begin with, can only have max of 2 PrefDirs on a
12586 
12587  // given element as can't select 2-track elements
12588  if(!(Track->FindNonPlatformMatch(8, HLoc, VLoc, EndPosition, TrackElement))) // return if can't find one
12589  {
12590  Utilities->CallLogPop(214);
12591  return false;
12592  }
12593 
12594  if(Track->IsLCAtHV(19, HLoc, VLoc))
12595  {
12596  TrainController->StopTTClockMessage(72, "Can't end a route on a level crossing");
12597  Utilities->CallLogPop(1908);
12598  return false;
12599  }
12600 
12601 // cancel selection if on original start element
12602  if(EndPosition == StartRoutePosition)
12603  {
12604  Utilities->CallLogPop(215);
12605  return false;
12606  }
12607  if(AutoSigsFlag)
12608  {
12609  if(TrackElement.TrackType == Buffers)
12610  {
12611  TrainController->StopTTClockMessage(19, "Can't create an automatic signal route into buffers");
12612  Utilities->CallLogPop(216);
12613  return false;
12614  }
12615  }
12616  if(ConsecSignalsRoute)
12617  {
12618  if((TrackElement.TrackType != SignalPost) && (TrackElement.TrackType != Buffers) && (TrackElement.TrackType != Continuation))
12619  {
12620  TrainController->StopTTClockMessage(20, "Must select a valid signal, buffers or continuation");
12621  Utilities->CallLogPop(217);
12622  return false;
12623  }
12624  }
12625  else // not needed now can't have preferred non-consec signals routes, but leave in
12626  {
12627  if((TrackElement.TrackType == Points) || (TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Crossover))
12628  {
12629  TrainController->StopTTClockMessage(21, "Can't select points, bridge or crossover when building a route");
12630 // makes later adjacent route checks too complicated
12631  Utilities->CallLogPop(218);
12632  return false;
12633  }
12634  }
12635 
12636 // check if train on element
12637  if(TrackElement.TrainIDOnElement > -1)
12638  {
12639  TrainController->StopTTClockMessage(22, "Can't end a route on a train");
12640  Utilities->CallLogPop(219);
12641  return false;
12642  }
12643 
12644 // disallow if not in EveryPrefDir & set EndElement(s)
12645  bool InPrefDirFlag = false;
12646 
12647  bool FoundFlag;
12648  int PrefDirPos0 = -1;
12649  int PrefDirPos1 = -1;
12650  int PrefDirPos2 = -1;
12651  int PrefDirPos3 = -1;
12652 
12653  EveryPrefDir->GetVectorPositionsFromPrefDir4MultiMap(4, Track->TrackElementAt(86, EndPosition).HLoc, Track->TrackElementAt(87, EndPosition).VLoc, FoundFlag,
12654  PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
12655  int PrefDirVecPos[4] =
12656  {PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3};
12657 
12658  for(int x = 0; x < 4; x++)
12659  {
12660  int b = PrefDirVecPos[x];
12661  if(b > -1)
12662  {
12663  InPrefDirFlag = true;
12664  if(EndElement1.TrackVectorPosition == -1)
12665  EndElement1 = EveryPrefDir->GetFixedPrefDirElementAt(33, b);
12666  else
12667  EndElement2 = EveryPrefDir->GetFixedPrefDirElementAt(34, b);
12668  }
12669  }
12670  if(!InPrefDirFlag)
12671  {
12673  "Route and preferred direction mismatch. If no preferred direction then only red routes can be used. Green and blue route directions must correspond to the preferred direction.");
12674  Utilities->CallLogPop(220);
12675  return false;
12676  }
12677 
12678 // check if in an existing route - can't be a bridge so can use a simple 'find'
12679 // bool InRoute = false;
12681  TAllRoutes::TRouteElementPair RoutePair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(15, TrackElement.HLoc, TrackElement.VLoc, DummyPair);
12682 
12683  if(RoutePair.first > -1)
12684  {
12685  if(RoutePair.second != 0) // not first element in existing route so no good
12686  {
12687  TrainController->StopTTClockMessage(24, "Can't end a route within or at the end of an existing route");
12688  Utilities->CallLogPop(221);
12689  return false;
12690  }
12691  TPrefDirElement RouteElement = AllRoutes->GetFixedRouteAt(8, RoutePair.first).GetFixedPrefDirElementAt(35, RoutePair.second);
12692 // if((RouteElement.Config[RouteElement.ELinkPos] != End) && (AllRoutes->TrackIsInARoute(, RouteElement.Conn[RouteElement.ELinkPos], RouteElement.ELinkPos)))
12693  if((RouteElement.Config[RouteElement.ELinkPos] != End) && (AllRoutes->TrackIsInARoute(10, RouteElement.Conn[RouteElement.ELinkPos],
12694  RouteElement.ConnLinkPos[RouteElement.ELinkPos]))) // amended at v1.3.0 - had omitted ConnLinkPos - see above
12695  // discovered when timetable building for Joshua Coupe's railway. Also affects non-preferred routes - see below
12696  // first element in existing route but that route linked to another route (or a non-bridge 2-track element containing a route) so no good
12697  {
12698  TrainController->StopTTClockMessage(25, "Can't start a route within or at the end of an existing route");
12699  Utilities->CallLogPop(222);
12700  return false;
12701  }
12702  EndElement1 = RouteElement;
12703  EndElement2 = BlankElement; // only need the route element
12704  EndPosition = EndElement1.TrackVectorPosition;
12705  ReqPosRouteID = IDInt(AllRoutes->GetFixedRouteAt(160, RoutePair.first).RouteID);
12706  }
12707 
12708 // set the H&V limits for the search, all points on search path must lie within 15 elements greater than the box of which the line between
12709 // start and finish is a diagonal line [dropped as not a good strategy because gaps interfered with direct line searches - instead
12710 // introduced TotalSearchCount and now use that to limit searches. Leave in though in case rethink strategy later on]
12711 
12712  if(EndElement1.HLoc >= StartElement1.HLoc)
12713  {
12715  SearchLimitHighH = EndElement1.HLoc + 15;
12716  }
12717  else
12718  {
12719  SearchLimitLowH = EndElement1.HLoc - 15;
12721  }
12722 
12723  if(EndElement1.VLoc >= StartElement1.VLoc)
12724  {
12726  SearchLimitHighV = EndElement1.VLoc + 15;
12727  }
12728  else
12729  {
12730  SearchLimitLowV = EndElement1.VLoc - 15;
12732  }
12733 /* dropped this for v0.4d - prevents ability to set routes for gaps that are widely separated, ok without it as search limited by SearchVector size
12734  check & TotalSearchCounts check
12735  if((abs(EndElement1.HLoc - StartElement1.HLoc) > 120) || (abs(EndElement1.VLoc - StartElement1.VLoc) > 120))
12736  {
12737  TrainController->StopTTClockMessage(65, "Unable to reach the selected element - too far ahead");
12738  Utilities->CallLogPop(1693);
12739  return false;
12740  }
12741 */
12742 // check if adjacent to start and disallow
12743  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
12744  {
12746  int AdjLinkPos = AllRoutes->GetFixedRouteAt(218, a).GetFixedPrefDirElementAt(244, 0).ELinkPos; // added at v1.3.1
12747 // if((EndElement1.Config[EndElement1.XLinkPos] != End) &&
12748 // (EndElement1.Conn[EndElement1.XLinkPos] == AdjPosition))
12749  if((EndElement1.Config[EndElement1.XLinkPos] != End) && (EndElement1.Conn[EndElement1.XLinkPos] == AdjPosition)
12750  && // changed at v1.3.1 to allow a route end adjacent to an element with a route that doesn't link to the ending route
12751  (EndElement1.ConnLinkPos[EndElement1.XLinkPos] == AdjLinkPos))
12752  {
12753  TrainController->StopTTClockMessage(26, "Can't end a route adjacent to the start of an existing route");
12754  Utilities->CallLogPop(223);
12755  return false;
12756  }
12757 // else if((EndElement2.TrackVectorPosition > -1) && (EndElement2.Config[EndElement2.XLinkPos] != End) &&
12758 // (EndElement2.Conn[EndElement2.XLinkPos] == AdjPosition))
12759  else if((EndElement2.TrackVectorPosition > -1) && (EndElement2.Config[EndElement2.XLinkPos] != End)
12760  && // changed at v1.3.1 to allow a route end adjacent to an element with a route that doesn't link to the ending route
12761  (EndElement2.Conn[EndElement2.XLinkPos] == AdjPosition) && (EndElement2.ConnLinkPos[EndElement2.XLinkPos] == AdjLinkPos))
12762  {
12763  TrainController->StopTTClockMessage(27, "Can't end a route adjacent to the start of an existing route");
12764  Utilities->CallLogPop(224);
12765  return false;
12766  }
12767 
12768 // check if adjacent to end of a route & disallow
12770  if((EndOfRouteElement.Config[EndOfRouteElement.XLinkPos] != End) && (EndOfRouteElement.Conn[EndOfRouteElement.XLinkPos] == EndPosition))
12771  {
12772  TrainController->StopTTClockMessage(28, "Can't end a route adjacent to the end of an existing route");
12773  Utilities->CallLogPop(225);
12774  return false;
12775  }
12776  }
12777 
12778 // check for same route as start element
12780  {
12781  TrainController->StopTTClockMessage(29, "Can't select same route as started in");
12782  Utilities->CallLogPop(226);
12783  return false;
12784  }
12785 
12786 // check for a looping route
12787  if((ReqPosRouteID > -1) && (StartSelectionRouteID > -1))
12788  {
12790  {
12791  TrainController->StopTTClockMessage(69, "Can't create a route that loops back on itself");
12792  Utilities->CallLogPop(1844);
12793  return false;
12794  }
12795  }
12796 
12797 // if there's a StartSelectionRouteID StartElement1 will be set to the last entry in the selected route
12798 // so search from this element. No need to add StartElement to the SearchVector since it already exists in a route
12799 // and don't want to add it again
12800  if(StartSelectionRouteID > -1)
12801  {
12802  if(SearchForPreferredRoute(0, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignalsRoute, EndPosition,
12803  AutoSigsFlag))
12804  {
12805  SetRouteSearchVectorGraphics(0, AutoSigsFlag, true); // change graphic colour to the route colour
12806  if(PointsToBeChanged(5))
12807  {
12808  PointsChanged = true;
12809  }
12810  Utilities->CallLogPop(227);
12811  return true;
12812  }
12813  else if(ConsecSignalsRoute && !Track->LCFoundInAutoSigsRouteMessageGiven)
12815  Utilities->CallLogPop(228);
12816  return false;
12817  }
12818  else
12819  {
12820 // Note: StartElement not in an existing route so was added to the searchvector during the earlier function
12821 // First check if selection adjacent to start element and if so use that [can't be as can't have 2 consecutive signals, but leave in]
12822 
12823 // added the XLinkPos checks because of Matt Blades error reported on 28/06/11, where StartElement2 matched EndPosition spuriously
12824 // note that a blank element will have XLinkPos set to -1
12825  if((StartElement1.XLinkPos > -1) && (StartElement1.Conn[StartElement1.XLinkPos] == EndPosition))
12826  {
12827  if(SearchForPreferredRoute(1, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignalsRoute, EndPosition,
12828  AutoSigsFlag))
12829  {
12830  SetRouteSearchVectorGraphics(1, AutoSigsFlag, true); // change graphic colour to the route colour
12831  if(PointsToBeChanged(6))
12832  {
12833  PointsChanged = true;
12834  }
12835  Utilities->CallLogPop(229);
12836  return true;
12837  }
12838  else
12839  {
12842  Utilities->CallLogPop(230);
12843  return false;
12844  }
12845  }
12846  else if((StartElement2.XLinkPos > -1) && (StartElement2.Conn[StartElement2.XLinkPos] == EndPosition))
12847  {
12848  if(SearchForPreferredRoute(2, StartElement2, StartElement2.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignalsRoute, EndPosition,
12849  AutoSigsFlag))
12850  {
12851  SetRouteSearchVectorGraphics(2, AutoSigsFlag, true); // change graphic colour to the route colour
12852  if(PointsToBeChanged(7))
12853  {
12854  PointsChanged = true;
12855  }
12856  Utilities->CallLogPop(231);
12857  return true;
12858  }
12859  else
12860  {
12863  Utilities->CallLogPop(232);
12864  return false;
12865  }
12866  }
12867 
12868  // now start off in the best direction
12869  int BestPos = Track->FindClosestLinkPosition(0, StartRoutePosition, EndPosition); // can only be 0 or 1
12870  // the following logic is very unstructured as extra bits have been added at different times and I'm reluctant to remove earlier bits in case
12871  // they cover situations that might be overlooked. A full analysis would enable it to be tidied up but it works (so far!) so I'll leave it as it is
12872  // unless new problems are found.
12873  if(StartElement1.XLinkPos == BestPos)
12874  {
12875  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
12876  if(SearchForPreferredRoute(3, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignalsRoute, EndPosition,
12877  AutoSigsFlag))
12878  {
12879  SetRouteSearchVectorGraphics(3, AutoSigsFlag, true); // change graphic colour to the route colour
12880  if(PointsToBeChanged(8))
12881  {
12882  PointsChanged = true;
12883  }
12884  Utilities->CallLogPop(233);
12885  return true;
12886  }
12887  else if(StartElement2.TrackVectorPosition > -1)
12888  {
12889  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
12890  if(SearchForPreferredRoute(4, StartElement2, StartElement2.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignalsRoute, EndPosition,
12891  AutoSigsFlag))
12892  {
12893  SetRouteSearchVectorGraphics(4, AutoSigsFlag, true); // change graphic colour to the route colour
12894  if(PointsToBeChanged(9))
12895  {
12896  PointsChanged = true;
12897  }
12898  Utilities->CallLogPop(234);
12899  return true;
12900  }
12901  }
12902  }
12903  else if(StartElement2.TrackVectorPosition > -1)
12904  {
12905  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
12906  if(SearchForPreferredRoute(5, StartElement2, StartElement2.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignalsRoute, EndPosition,
12907  AutoSigsFlag))
12908  {
12909  SetRouteSearchVectorGraphics(6, AutoSigsFlag, true); // change graphic colour to the route colour
12910  if(PointsToBeChanged(10));
12911  {
12912  PointsChanged = true;
12913  }
12914  Utilities->CallLogPop(1857);
12915  return true;
12916  }
12917  else if(SearchForPreferredRoute(8, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignalsRoute, EndPosition,
12918  AutoSigsFlag))
12919  {
12920  SetRouteSearchVectorGraphics(7, AutoSigsFlag, true); // change graphic colour to the route colour
12921  if(PointsToBeChanged(11));
12922  {
12923  PointsChanged = true;
12924  }
12925  Utilities->CallLogPop(1858);
12926  return true;
12927  }
12928  }
12929  else if(StartElement1.XLinkPos == (1 - BestPos))
12930  // added at v0.4d to use StartElement1 again with non-Best direction (may be only one & may not point in right direction
12931  {
12932  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
12933  if(SearchForPreferredRoute(9, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignalsRoute, EndPosition,
12934  AutoSigsFlag))
12935  {
12936  SetRouteSearchVectorGraphics(8, AutoSigsFlag, true); // change graphic colour to the route colour
12937  if(PointsToBeChanged(12))
12938  {
12939  PointsChanged = true;
12940  }
12941  Utilities->CallLogPop(1864);
12942  return true;
12943  }
12944  }
12945  }
12948  Utilities->CallLogPop(235);
12949  return false;
12950 }
12951 
12952 // ---------------------------------------------------------------------------
12953 
12954 void TOneRoute::RouteImageMarker(int Caller, Graphics::TBitmap *Bitmap) const
12955 {
12956  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RouteImageMarker");
12957  if(PrefDirSize() == 0)
12958  {
12959  Utilities->CallLogPop(1704);
12960  return;
12961  }
12962  for(unsigned int x = 0; x < PrefDirSize(); x++)
12963  {
12964  TPrefDirElement TempPrefDirElement = PrefDirVector.at(x);
12965  if(TempPrefDirElement.EXGraphicPtr != 0) // Note: will be 0 if first element or last as leading point
12966  {
12967  Bitmap->Canvas->Draw((TempPrefDirElement.HLoc - Track->GetHLocMin()) * 16, (TempPrefDirElement.VLoc - Track->GetVLocMin()) * 16,
12968  TempPrefDirElement.EXGraphicPtr);
12969  if((TempPrefDirElement.EntryDirectionGraphicPtr != 0) && PrefDirSize() > 1) // Route, no direction if a single element
12970  {
12971  if(x == 0)
12972  {
12973  Bitmap->Canvas->Draw((TempPrefDirElement.HLoc - Track->GetHLocMin()) * 16, (TempPrefDirElement.VLoc - Track->GetVLocMin()) * 16,
12974  TempPrefDirElement.EntryDirectionGraphicPtr);
12975  }
12976  if(x == (PrefDirSize() - 1))
12977  {
12978  Bitmap->Canvas->Draw((TempPrefDirElement.HLoc - Track->GetHLocMin()) * 16, (TempPrefDirElement.VLoc - Track->GetVLocMin()) * 16,
12979  TempPrefDirElement.EntryDirectionGraphicPtr);
12980  }
12981  }
12982  }
12983  }
12984 
12985  Utilities->CallLogPop(1705);
12986 }
12987 
12988 // ---------------------------------------------------------------------------
12989 
12990 bool TOneRoute::SearchForPreferredRoute(int Caller, TPrefDirElement PrefDirElement, int XLinkPos, int RequiredPosition, IDInt ReqPosRouteID,
12991  TOnePrefDir *EveryPrefDir, bool ConsecSignalsRoute, int EndPosition, bool AutoSigsFlag)
12992 
12993 /*
12994  Brief: similar to SearchForPrefDir but with a PrefDirElement instead of a TrackElement & with additional parameters.
12995  PrefDirElement is the starting element from which to search, it is NOT stored in searchvector during this function. If
12996  it's an element that's not already in a route it will have been stored in SearchVector during GetPreferredRouteStartElement.
12997  ReqPosRouteID is used when RequiredPosition is start of an existing route, else it's -1.
12998  Return false if any element (apart from RequiredPosition) is on an existing route.
12999  Return false if not on a PrefDir with same ELink (can't check XLink as may not be set - if it's a leading point).
13000 
13001  Detail: Function is a continuous loop as examine each element on a potential route, exiting only if find
13002  the required position (return true & leave Searchvector as set up) or if fail (erase all SearchVector entries
13003  added during the function so as to leave it exactly as it was on entering, then return false).
13004  It is a recursive function (similar to SearchForPrefDir) to enable all possible point branches to be searched.
13005  A VectorCount is maintained to count elements added to the SearchVector, so that this number can be erased on failure
13006  of any branch. Enter with starting PrefDirElement & XLinkPos for that element, RequiredPosition - the
13007  TrackVectorPosition of the element to be searched for, ReqPosRouteID -
13008  the route number that the searched-for element is the start of if any, and set to -1 if no
13009  such route. A pointer to EveryPrefDir is also passed in since this is not accessible directly from
13010  this unit, together with the ConsecSignalsRoute and AutoSigsFlag flags.
13011  Create 2 TPrefDirElements - PrefDirElement1 and 2, for use later - ELink has to match the preceding XLink, so the only
13012  2 possible PrefDirs are for a leading point & its two trailing PrefDirs.
13013 
13014  Enter loop - note that PrefDirElement changes each time round the loop - check if PrefDirElement XLinkPos faces buffers
13015  or a continuation, and fail if so. Check if reached a valid signal in ConsecSignalsRoute on any but firstpass
13016  (nonrecursive firstpass starts at a valid signal, and recursive firstpass always starts at points so doesn't matter
13017  for recursive calls), and fail if so as user should always select the next signal in a route.
13018  Create a new TPrefDirElement - SearchElement, from PrefDirElement.Conn[XLinkPos], & set all FixedTrackPiece &
13019  TrackElement values, ELink & ELinkPos, and also XLink & XLinkPos unless element is a leading point.
13020  Check if element is already in searchvector (OK if a bridge & earlier entry on different track, but not OK if
13021  any other type of element), already in an existing route (OK if bridge & diff tracks, or start of an expected route),
13022  or if train on element (unless a bridge & train on different track).
13023  Check & fail for a fouled diagonal (unless element is a leading point - these checked later).
13024  Check element in EveryPrefDir with same ELink value & set PrefDirElement1, & also 2 if element is
13025  a leading point where both trailing directions are in EveryPrefDir, if not fail.
13026  Check if found RequiredPosition & that it's a signal/buffer/continuation if ConsecSignalsRoute set. If OK save in SearchVector with
13027  AutoSignals member set if AutoSigsFlag set, then return true.
13028  Check & fail if a buffer or continuation (if element = RequiredPosition will have succeeded in the above check.
13029 
13030  Now check if a leading point and if so set XLinkPos to the 'set' exit & check if that XLink is in EveryPrefDir,
13031  by comparing with PrefDirElement1 or 2, fail if not. If valid check for a fouled diagonal and fail if so. If OK
13032  store element in SearchVector with AutoSignals member set if AutoSigsFlag set & do a recursive search using
13033  this element and XLinkPos, other parameters are passed in without change. If succeed return true, else erase the last element in
13034  SearchVector (i.e the earlier stored leading point element prior to doing the recursive search) & set XLinkPos to the 'unset' exit to
13035  check the other trailing direction. Then proceed in same way as above, i.e. fouled diagonal & recursive search etc. If
13036  fail on this XLinkPos then have tried & failed on both ways out from the leading point so erase the searchvector & return false.
13037 
13038  If not a leading point store the element (can only be PrefDirElement1 as not a leading point), then set
13039  up the next loop values of PrefDirElement & XLinkPos from SearchElement & NextXLinkPos and repeat the while loop.
13040 */
13041 
13042 {
13043  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchForPreferredRoute," + PrefDirElement.LogPrefDir() + "," +
13044  AnsiString(XLinkPos) + "," + AnsiString(RequiredPosition) + "," + AnsiString(ReqPosRouteID.GetInt()) + "," + AnsiString(EndPosition) + "," +
13045  AnsiString((short)AutoSigsFlag));
13046  int VectorCount = 0;
13047  TPrefDirElement PrefDirElement1, PrefDirElement2, BlankElement;
13048 
13049 // check for a fouled diagonal for first element. Added for v1.3.2
13050  if((PrefDirElement.XLink == 1) || (PrefDirElement.XLink == 3) || (PrefDirElement.XLink == 7) || (PrefDirElement.XLink == 9))
13051  {
13052  if(AllRoutes->DiagonalFouledByRouteOrTrain(0, PrefDirElement.HLoc, PrefDirElement.VLoc, PrefDirElement.XLink))
13053  {
13054  for(int x = 0; x < VectorCount; x++)
13055  SearchVector.erase(SearchVector.end() - 1);
13056  Utilities->CallLogPop(2043);
13057  return false;
13058  }
13059  }
13060 
13061  bool FirstPass = true;
13062 
13063  while(true)
13064  {
13065  if(AutoSigsFlag && Track->IsLCAtHV(24, PrefDirElement.HLoc, PrefDirElement.VLoc))
13066  {
13067  Track->LCFoundInAutoSigsRoute = true;
13068  }
13069  if(Track->IsLCBarrierFlashingAtHV(1, PrefDirElement.HLoc, PrefDirElement.VLoc)) // can't set a route through a flashing barrier
13070  {
13071  for(int x = 0; x < VectorCount; x++)
13072  SearchVector.erase(SearchVector.end() - 1);
13073  Utilities->CallLogPop(1926);
13074  return false;
13075  }
13076  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == End) // buffers or continuation
13077  {
13078  for(int x = 0; x < VectorCount; x++)
13079  SearchVector.erase(SearchVector.end() - 1);
13080  Utilities->CallLogPop(236);
13081  return false;
13082  }
13083  if(!FirstPass && (ConsecSignalsRoute) && (PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal))
13084  // reached a valid signal that isn't the required position, user should always select the next
13085  // signal in a route so have to fail
13086  // won't affect recurive searches as for them the first pass element is always a point
13087  {
13088  for(int x = 0; x < VectorCount; x++)
13089  SearchVector.erase(SearchVector.end() - 1);
13090  Utilities->CallLogPop(237);
13091  return false;
13092  }
13093  FirstPass = false;
13094  int NextPosition = PrefDirElement.Conn[XLinkPos];
13095  TTrackElement NextTrackElement = Track->TrackElementAt(88, NextPosition);
13096  TPrefDirElement SearchElement(NextTrackElement);
13097  SearchElement.TrackVectorPosition = NextPosition;
13098  int NextELinkPos = PrefDirElement.ConnLinkPos[XLinkPos];
13099  SearchElement.ELinkPos = NextELinkPos;
13100  SearchElement.ELink = SearchElement.Link[NextELinkPos]; // Note ELink isn't necessarily 10 - last XLink, as last element may have
13101  // been a gap. Now have all FixedTrackPiece & TrackElement values, + TrackVectorPosition, ELink & ELinkPos
13102  int NextXLinkPos;
13103  if(SearchElement.ELinkPos == 0)
13104  NextXLinkPos = 1;
13105  if(SearchElement.ELinkPos == 1)
13106  NextXLinkPos = 0;
13107  if(SearchElement.ELinkPos == 2)
13108  NextXLinkPos = 3;
13109  if(SearchElement.ELinkPos == 3)
13110  NextXLinkPos = 2;
13111  if((SearchElement.TrackType != Points) || (SearchElement.Config[SearchElement.ELinkPos] != Lead))
13112  {
13113  SearchElement.XLink = SearchElement.Link[NextXLinkPos];
13114 // note that may be buffers, continuation or gap
13115  SearchElement.XLinkPos = NextXLinkPos;
13116  }
13117 // can't set XLink or XLinkPos yet if the element is a leading point.
13118 
13119 // check if reached an earlier position on search PrefDir (was OK in SearchForPrefDir if entry values different, but not OK for a route)
13120  for(unsigned int x = 0; x < SearchVector.size(); x++)
13121  {
13122  if(SearchElement.TrackVectorPosition == SearchVector.at(x).TrackVectorPosition)
13123  {
13124  if((SearchElement.TrackType != Bridge) || ((SearchElement.TrackType == Bridge) && (SearchElement.ELink == SearchVector.at(x).ELink)))
13125  // OK if a bridge & routes on different tracks
13126  {
13127  for(int x = 0; x < VectorCount; x++)
13128  SearchVector.erase(SearchVector.end() - 1);
13129  Utilities->CallLogPop(238);
13130  return false;
13131  }
13132  }
13133  }
13134 
13135 // check if element in an existing route (OK if bridge & diff tracks, or start of an expected route)
13136  TAllRoutes::TRouteElementPair SecondPair;
13138  Track->TrackElementAt(89, SearchElement.TrackVectorPosition).HLoc, Track->TrackElementAt(90, SearchElement.TrackVectorPosition).VLoc, SecondPair);
13139  if(RoutePair.first > -1)
13140  {
13141  // OK if it's a bridge & routes on different tracks (hard to see how can reach a bridge before another element in route as can't start on a bridge, but leave check in anyway)
13142  if(!((SearchElement.TrackType == Bridge) && (SearchElement.ELinkPos != AllRoutes->GetFixedRouteAt(12, RoutePair.first).GetFixedPrefDirElementAt(38,
13143  RoutePair.second).ELinkPos)))
13144  {
13145  // still OK if start of an expected route
13146  if((ReqPosRouteID == IDInt(-1)) || ((int)RoutePair.first != AllRoutes->GetRouteVectorNumber(2, ReqPosRouteID)) || (RoutePair.second != 0))
13147  {
13148  for(int x = 0; x < VectorCount; x++)
13149  SearchVector.erase(SearchVector.end() - 1);
13150  Utilities->CallLogPop(239);
13151  return false; // only allow for start of an expected route
13152  }
13153  }
13154  }
13155  if(SecondPair.first > -1) // if reach here & secondpair present then must fail as can't escape both existing routes, but leave check as before anyway
13156  {
13157  // OK if it's a bridge & routes on different tracks (hard to see how can reach a bridge before another element in route as can't start on a bridge, but leave check in anyway)
13158  if(!((SearchElement.TrackType == Bridge) && (SearchElement.ELinkPos != AllRoutes->GetFixedRouteAt(13, SecondPair.first).GetFixedPrefDirElementAt(39,
13159  SecondPair.second).ELinkPos)))
13160  {
13161  // still OK if start of an expected route
13162  if((ReqPosRouteID == IDInt(-1)) || ((int)SecondPair.first != AllRoutes->GetRouteVectorNumber(3, ReqPosRouteID)) || (SecondPair.second != 0))
13163  {
13164  for(int x = 0; x < VectorCount; x++)
13165  SearchVector.erase(SearchVector.end() - 1);
13166  Utilities->CallLogPop(240);
13167  return false; // only allow for start of an expected route
13168  }
13169  }
13170  }
13171 
13172 // check if a train on element, unless a bridge & train on different track
13173 // OK of same train as start element - no drop this
13174 // if(SearchElement.TrainIDOnElement != StartSelectionTrainID)
13175  if((SearchElement.TrainIDOnElement > -1) && (SearchElement.TrackType != Bridge))
13176  {
13177  for(int x = 0; x < VectorCount; x++)
13178  SearchVector.erase(SearchVector.end() - 1);
13179  Utilities->CallLogPop(241);
13180  return false;
13181  }
13182  if((SearchElement.TrainIDOnElement > -1) && (SearchElement.TrackType == Bridge))
13183  {
13184  if((SearchElement.ELinkPos < 2) && (SearchElement.TrainIDOnBridgeTrackPos01 > -1))
13185  {
13186  for(int x = 0; x < VectorCount; x++)
13187  SearchVector.erase(SearchVector.end() - 1);
13188  Utilities->CallLogPop(242);
13189  return false;
13190  }
13191  else if((SearchElement.ELinkPos > 1) && (SearchElement.TrainIDOnBridgeTrackPos23 > -1))
13192  {
13193  for(int x = 0; x < VectorCount; x++)
13194  SearchVector.erase(SearchVector.end() - 1);
13195  Utilities->CallLogPop(243);
13196  return false;
13197  }
13198  }
13199 
13200 // check for a fouled diagonal (if not leading point - these checked later - leading point XLink == -1)
13201  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
13202  {
13203  if(AllRoutes->DiagonalFouledByRouteOrTrain(7, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
13204  {
13205  for(int x = 0; x < VectorCount; x++)
13206  SearchVector.erase(SearchVector.end() - 1);
13207  Utilities->CallLogPop(244);
13208  return false;
13209  }
13210  }
13211 // check element in EveryPrefDir with same ELink (XLink may not be set) & save up to 2 elements (for leading point & 2 trailing PrefDirs)
13212 // note that point XLinks checked later, otherwise XLink fully defined by ELink so only need to check ELink
13213  bool InPrefDirFlag = false;
13214  PrefDirElement1 = BlankElement;
13215  PrefDirElement2 = BlankElement;
13216 
13217  bool FoundFlag;
13218  int PrefDirPos0 = -1;
13219  int PrefDirPos1 = -1;
13220  int PrefDirPos2 = -1;
13221  int PrefDirPos3 = -1;
13223  Track->TrackElementAt(92, SearchElement.TrackVectorPosition).VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
13224  int PrefDirVecPos[4] =
13225  {PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3};
13226  for(int x = 0; x < 4; x++)
13227  {
13228  int b = PrefDirVecPos[x];
13229  if((b > -1) && (EveryPrefDir->GetFixedPrefDirElementAt(40, b).ELink == SearchElement.ELink))
13230  {
13231  InPrefDirFlag = true;
13232  if(PrefDirElement1.TrackVectorPosition == -1)
13233  PrefDirElement1 = EveryPrefDir->GetFixedPrefDirElementAt(41, b);
13234  else
13235  PrefDirElement2 = EveryPrefDir->GetFixedPrefDirElementAt(42, b);
13236  }
13237  }
13238  if(!InPrefDirFlag)
13239  {
13240  for(int x = 0; x < VectorCount; x++)
13241  SearchVector.erase(SearchVector.end() - 1);
13242  Utilities->CallLogPop(245);
13243  return false;
13244  }
13245 
13246 // check if exceeds the search H & V limits - drop in favour of limiting TotalSearchCount
13247 // if((SearchElement.HLoc > SearchLimitHighH) || (SearchElement.HLoc < SearchLimitLowH) ||
13248 // (SearchElement.VLoc > SearchLimitHighV) ||(SearchElement.VLoc < SearchLimitLowV))
13250  {
13251  for(int x = 0; x < VectorCount; x++)
13252  SearchVector.erase(SearchVector.end() - 1);
13253  Utilities->CallLogPop(1690);
13254  return false;
13255  }
13256 
13257 // check if found it
13258  if(SearchElement.TrackVectorPosition == RequiredPosition)
13259  {
13260 // need to ensure a signal/buffer/continuation if ConsecSignalsRoute set,
13261  if(ConsecSignalsRoute && (SearchElement.Config[SearchElement.XLinkPos] != Signal) && (SearchElement.Config[SearchElement.XLinkPos] != End) &&
13262  (SearchElement.Config[SearchElement.XLinkPos] != Continuation))
13263  {
13264  for(int x = 0; x < VectorCount; x++)
13265  SearchVector.erase(SearchVector.end() - 1);
13266  Utilities->CallLogPop(246);
13267  return false;
13268  } // if(ConsecSignalsRoute && (SearchElement.Config[SearchElement.XLinkPos] != Signal).......
13269  if(AutoSigsFlag)
13270  {
13271  PrefDirElement1.AutoSignals = true;
13272  }
13273  if(ConsecSignalsRoute)
13274  {
13275  PrefDirElement1.ConsecSignals = true;
13276  }
13278  {
13280  {
13281  TrainController->StopTTClockMessage(76, "Can't create an automatic signal route through a level crossing");
13283  }
13284  for(int x = 0; x < VectorCount; x++)
13285  SearchVector.erase(SearchVector.end() - 1);
13286  Utilities->CallLogPop(1928);
13287  return false;
13288  }
13289  SearchVector.push_back(PrefDirElement1); // must be 1 as it's a simple element
13290  VectorCount++; // not really needed but include for tidyness
13291  TotalSearchCount++;
13292  Utilities->CallLogPop(247);
13293  return true;
13294  } // if(SearchElement.TrackVectorPosition == RequiredPosition)
13295 // check if a buffer or continuation (end of search on this leg if not found by now)
13296  if((SearchElement.TrackType == Buffers) || (SearchElement.TrackType == Continuation))
13297  {
13298  for(int x = 0; x < VectorCount; x++)
13299  SearchVector.erase(SearchVector.end() - 1);
13300  Utilities->CallLogPop(248);
13301  return false;
13302  }
13303 // check if SearchVector exceeds a size of 150
13304  if(SearchVector.size() > 150)
13305  {
13306  for(int x = 0; x < VectorCount; x++)
13307  SearchVector.erase(SearchVector.end() - 1);
13308  Utilities->CallLogPop(1420);
13309  return false;
13310  }
13311 // check if reached a leading point
13312  if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Lead))
13313  {
13314 // XLink set to points 'set' position - Attribute == 0, SearchPos1 = 1 & SearchPos2 = 3; Attribute == 1, SearchPos1 = 3 & SearchPos2 = 1;
13315  int SearchPos1 = SearchElement.Attribute + 1;
13316  int SearchPos2;
13317  if(SearchPos1 == 2)
13318  SearchPos1++;
13319  if(SearchPos1 == 1)
13320  SearchPos2 = 3;
13321  else
13322  SearchPos2 = 1;
13323  SearchElement.XLink = SearchElement.Link[SearchPos1];
13324  SearchElement.XLinkPos = SearchPos1;
13325  InPrefDirFlag = false;
13326  if(SearchElement.XLink == PrefDirElement1.XLink)
13327  {
13328  SearchElement = PrefDirElement1; // set to an existing PrefDir element so that exnumber & graphics set
13329  InPrefDirFlag = true;
13330  }
13331  else if(SearchElement.XLink == PrefDirElement2.XLink)
13332  {
13333  SearchElement = PrefDirElement2;
13334  InPrefDirFlag = true;
13335  }
13336 // push element with XLink set to position [SearchPos1] if on a PrefDir
13337  if(InPrefDirFlag)
13338  {
13339 // check for a fouled diagonal for leading point for XLinkPos == 1)
13340  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
13341  {
13342  if(AllRoutes->DiagonalFouledByRouteOrTrain(1, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
13343  {
13344  for(int x = 0; x < VectorCount; x++)
13345  SearchVector.erase(SearchVector.end() - 1);
13346  Utilities->CallLogPop(249);
13347  return false;
13348  }
13349  }
13350  if(AutoSigsFlag)
13351  {
13352  SearchElement.AutoSignals = true;
13353  }
13354  if(ConsecSignalsRoute)
13355  {
13356  SearchElement.ConsecSignals = true;
13357  }
13358  SearchVector.push_back(SearchElement);
13359  VectorCount++;
13360  TotalSearchCount++;
13361 // recursive search at XLinkPos of SearchPos1 (i.e. 'set' trailing exit)
13362  if(SearchForPreferredRoute(6, SearchElement, SearchPos1, RequiredPosition, ReqPosRouteID, EveryPrefDir, ConsecSignalsRoute, EndPosition,
13363  AutoSigsFlag))
13364  {
13366  {
13368  {
13369  TrainController->StopTTClockMessage(77, "Can't create an automatic signal route through a level crossing");
13371  }
13372  for(int x = 0; x < VectorCount; x++)
13373  SearchVector.erase(SearchVector.end() - 1);
13374  Utilities->CallLogPop(1929);
13375  return false;
13376  }
13377  Utilities->CallLogPop(250);
13378  return true;
13379  }
13380  else
13381  {
13382 // remove leading point with XLinkPos [1]
13383  SearchVector.erase(SearchVector.end() - 1);
13384  VectorCount--;
13385  }
13386  }
13387 // XLink set to position [SearchPos2]
13388  SearchElement.XLink = SearchElement.Link[SearchPos2];
13389  SearchElement.XLinkPos = SearchPos2;
13390  if(SearchElement.XLink == PrefDirElement1.XLink)
13391  {
13392  SearchElement = PrefDirElement1; // set to an existing PrefDir element so that exnumber & graphics set
13393  }
13394  else if(SearchElement.XLink == PrefDirElement2.XLink)
13395  {
13396  SearchElement = PrefDirElement2;
13397  }
13398  else // failed to find a valid exit from the point
13399  {
13400  for(int x = 0; x < VectorCount; x++)
13401  SearchVector.erase(SearchVector.end() - 1);
13402  Utilities->CallLogPop(251);
13403  return false;
13404  }
13405 // check for a fouled diagonal for leading point for XLinkPos == SearchPos2)
13406  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
13407  {
13408  if(AllRoutes->DiagonalFouledByRouteOrTrain(2, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
13409  {
13410  for(int x = 0; x < VectorCount; x++)
13411  SearchVector.erase(SearchVector.end() - 1);
13412  Utilities->CallLogPop(252);
13413  return false;
13414  }
13415  }
13416 // push element with XLink set to position [SearchPos2]
13417  if(AutoSigsFlag)
13418  {
13419  SearchElement.AutoSignals = true;
13420  }
13421  if(ConsecSignalsRoute)
13422  {
13423  SearchElement.ConsecSignals = true;
13424  }
13425  SearchVector.push_back(SearchElement);
13426  VectorCount++;
13427  TotalSearchCount++;
13428 // recursive search at XLinkPos of SearchPos2 (i.e. 'unset' trailing exit)
13429  if(SearchForPreferredRoute(7, SearchElement, SearchPos2, RequiredPosition, ReqPosRouteID, EveryPrefDir, ConsecSignalsRoute, EndPosition,
13430  AutoSigsFlag))
13431  {
13433  {
13435  {
13436  TrainController->StopTTClockMessage(78, "Can't create an automatic signal route through a level crossing");
13438  }
13439  for(int x = 0; x < VectorCount; x++)
13440  SearchVector.erase(SearchVector.end() - 1);
13441  Utilities->CallLogPop(1930);
13442  return false;
13443  }
13444  Utilities->CallLogPop(1592);
13445  return true;
13446  }
13447  else
13448  {
13449  for(int x = 0; x < VectorCount; x++)
13450  SearchVector.erase(SearchVector.end() - 1);
13451  Utilities->CallLogPop(253);
13452  return false;
13453  }
13454  } // if leading point
13455 // here if ordinary element, push it, inc vector & update PrefDirElement ready for next element on PrefDir
13456  SearchElement = PrefDirElement1;
13457  if(AutoSigsFlag)
13458  {
13459  SearchElement.AutoSignals = true;
13460  }
13461  if(ConsecSignalsRoute)
13462  {
13463  SearchElement.ConsecSignals = true;
13464  }
13465  SearchVector.push_back(SearchElement);
13466  VectorCount++;
13467  TotalSearchCount++;
13468  XLinkPos = SearchElement.XLinkPos; // wasn't a leading point so XLinkPos defined
13469  PrefDirElement = SearchElement;
13470  } // while(true)
13471 }
13472 
13473 // ---------------------------------------------------------------------------
13474 
13475 void TOneRoute::ConvertAndAddPreferredRouteSearchVector(int Caller, IDInt ReqPosRouteID, bool AutoSigsFlag)
13476 {
13477 /*
13478  For routes, as opposed to PrefDirs, the new route elements are first entered into SearchVector,
13479  and the new or extended route created from that. Hence action varies depending on whether
13480  it is a completely new route, or an extension of an existing route at the beginning or the end.
13481  Note that a single route cannot contain both AutoSig & non-AutoSig elements, each route of AutoSig elements
13482  has its own identity. A single route can however have a mixture of Unrestricted and PreferredRoute elements
13483 
13484  Ignore if SearchVector empty, and check that all the new elements in SearchVector are valid.
13485  Check if route end selection is in an existing route (ReqPosRouteID > -1), and if so proceed as follows:-
13486  if both new and existing routes non-autosig, add the old route to the SearchVector then delete the old route;
13487  if both new and existing routes autosig, add the old route to the SearchVector then delete the old route;
13488  in both the above cases if RequPosRouteNumber is less than StartSelectionRouteNumber then StartSelectionRouteNumber
13489  is decremented;
13490  if new route autosig and existing route non-autosig, keep the final search element in the new route & remove it (i.e first element)
13491  from the existing route, then enter the new route into the AllRoutesVector;
13492  if new route non-autosig and existing route autosig, drop the final search element in the new route, leave the existing route as it is,
13493  then enter the new route into the AllRoutesVector.
13494 
13495  Check if StartSelectionRouteID set (extending an existing route) and if so proceed as follows:-
13496  if both new and existing routes non-autosig, then add the new route to the existing route (start element not stored in searchvector);
13497  if both new and existing routes autosig, then add the new route to the existing route (start element not stored in searchvector);
13498  in both the above cases validate the extended route, then call SetRoutePoints & SetRouteSignals for the extended route and return.
13499  if new route autosig and existing route non-autosig, remove the last route element from the existing route, make it an AutoSig element,
13500  then add it to the start of the new route, then check its validity, enter it into the AllRoutesVector, call SetRoutePoints & SetRouteSignals
13501  for the new route and return;
13502  if new route non-autosig and existing route autosig, leave the existing route as it is, check its validity, then just enter the new
13503  route into the AllRoutesVector, finally call SetRoutePoints & SetRouteSignals for the new route and return.
13504 
13505  If not returned by now the route in SearchVector is to be added as a new route, so check its validity, create a new route using
13506  StoreOneRoute, call SetRoutePoints & SetRouteSignals and return. In practice the validity check, storage into AllRoutesVector and
13507  SetRoutePoints & SetRouteSignals call are combined for the above three cases.
13508 */
13509  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConvertAndAddPreferredRouteSearchVector," +
13510  AnsiString(ReqPosRouteID.GetInt()) + "," + AnsiString((short)AutoSigsFlag));
13511  if(SearchVector.size() < 1)
13512  {
13513  Utilities->CallLogPop(254);
13514  return;
13515  }
13517  if(!ValidatePrefDir(3)) // check the new route elements in SearchVector
13518  {
13519  Utilities->CallLogPop(255);
13520  return;
13521  }
13522 
13523  TAllRoutes::TLockedRouteClass LockedRouteObject;
13524 
13526  unsigned int TruncatePrefDirPosition = 0;
13527 
13528  if(ReqPosRouteID > -1) // Note that ReqPosRouteID != StartRouteNumber as would have failed in GetNextRouteElement
13529 /* if have ReqPosRouteID:
13530  if both new and existing routes non-autosig, then add the old route to the SearchVector then delete the old route
13531  if both new and existing routes autosig, then add the old route to the SearchVector then delete the old route
13532  if new route autosig and existing route non-autosig, keep the final search element in the new route & remove it (i.e first element) from
13533  the existing route, then enter the new route into the AllRoutesVector
13534  if new route non-autosig and existing route autosig, drop the final search element in the new route, leave the existing route as it is,
13535  then enter the new route into the AllRoutesVector
13536 */
13537  {
13540  {
13541  for(unsigned int x = 1; x < AllRoutes->GetFixedRouteAtIDNumber(21, ReqPosRouteID).PrefDirSize();
13542  x++) // start at 1 as first element already in SearchVector
13543  {
13545  }
13546  // note that route numbers in map adjusted when ReqPos route cleared
13548  // create a new locked route object (apart from RouteNumber) if required, for use later (LockedRouteFoundDuringRouteBuilding
13549  // set during ClearRouteDuringRouteBuildingAt
13551  {
13554  LockedRouteObject.LastXLinkPos = AllRoutes->LockedRouteLastXLinkPos;
13555  LockedRouteObject.LockStartTime = AllRoutes->LockedRouteLockStartTime;
13556  }
13557  }
13559  {
13561  AllRoutes->RemoveRouteElement(3, RouteElement.HLoc, RouteElement.VLoc, RouteElement.ELink);
13562  }
13564  {
13565  SearchVector.pop_back();
13566  }
13567  }
13568 
13569  if(StartSelectionRouteID > -1)
13570 /* if have StartSelectionRouteID:
13571  if both new and existing routes non-autosig, then add the new route to the existing route (start element not stored in searchvector)
13572  if both new and existing routes autosig, then add the new route to the existing route (start element not stored in searchvector)
13573  if new route autosig and existing route non-autosig, remove the last route element from the existing route, make it an AutoSig element,
13574  then add it to the start of the new route, then enter the new route into the AllRoutesVector
13575  if new route non-autosig and existing route autosig, leave the existing route as it is, and just enter the new route into the AllRoutesVector
13576 */
13577  {
13579  // need to test because may have been removed by a train moving in the wrong direction between first and last route selections - added at v1.3.1
13580  {
13583  {
13584  int RouteNumber = AllRoutes->GetRouteVectorNumber(0, StartSelectionRouteID);
13585  for(unsigned int x = 0; x < SearchVector.size(); x++)
13586  {
13588  RouteNumber, GetFixedSearchElementAt(3, x));
13589  // find & store locked route truncate position in PrefDirVector for later use
13591  {
13592  if(GetFixedSearchElementAt(15, x).TrackVectorPosition == int(AllRoutes->LockedRouteTruncateTrackVectorPosition))
13593  {
13594  TruncatePrefDirPosition = AllRoutes->GetFixedRouteAt(172, RouteNumber).PrefDirSize() - 1;
13595  }
13596  }
13597  }
13599  {
13600  throw Exception("Error - failed to validate extended route for preferred route");
13601  }
13604  if(!AutoSigsFlag)
13605  {
13606  AllRoutes->GetModifiableRouteAtIDNumber(7, StartSelectionRouteID).SetLCChangeValues(0, true); // ConsecSignalsRoute is true
13607  }
13608  // now add the reinstated locked route if required and set signals accordingly
13610  {
13611  LockedRouteObject.RouteNumber = RouteNumber;
13612  AllRoutes->LockedRouteVector.push_back(LockedRouteObject);
13613  // now reset the signals for the locked route
13614  AllRoutes->SetAllRearwardsSignals(9, 0, RouteNumber, TruncatePrefDirPosition);
13615  for(int c = AllRoutes->GetFixedRouteAt(173, RouteNumber).PrefDirSize() - 1; c >= (int)TruncatePrefDirPosition;
13616  c--) // must use int for >= test to succeed when TruncatePrefDirPosition == 0
13617  // return all signals to red in route section to be truncated
13618  {
13619  TPrefDirElement PrefDirElement = AllRoutes->GetFixedRouteAt(174, RouteNumber).PrefDirVector.at(c);
13620  TTrackElement & TrackElement = Track->TrackElementAt(812, PrefDirElement.TrackVectorPosition);
13621  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal)
13622  {
13623  TrackElement.Attribute = 0;
13624  Track->PlotSignal(10, TrackElement, Display);
13625  Display->PlotOutput(113, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EXGraphicPtr);
13626  Display->PlotOutput(114, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EntryDirectionGraphicPtr);
13627  }
13628  }
13629  }
13630  AllRoutes->CheckMapAndRoutes(1); // test
13631  Utilities->CallLogPop(256);
13632  return;
13633  }
13635  {
13638  RouteElement.AutoSignals = true;
13639  RouteElement.EXGraphicPtr = RouteElement.GetRouteGraphicPtr(AutoSigsFlag, true); // true for ConsecSignalsRoute
13640  RouteElement.EntryDirectionGraphicPtr = RouteElement.GetDirectionRouteGraphicPtr(AutoSigsFlag, true); // true for ConsecSignalsRoute
13641  AllRoutes->RemoveRouteElement(4, RouteElement.HLoc, RouteElement.VLoc, RouteElement.ELink);
13642  SearchVector.insert(SearchVector.begin(), 1, RouteElement);
13643  }
13644  }
13645  else
13646  {
13648  }
13649 // if new route non-autosig and existing route autosig, leave the existing route as it is, and just enter the new route into the
13650 // AllRoutesVector hence nothing to do here
13651  }
13652 
13653  PrefDirVector = SearchVector; // need to copy again since SearchVector may have been extended
13654  if(!ValidatePrefDir(5)) // validate PrefDir for all new route elements
13655  {
13656  throw Exception("Error - failed to validate single route for preferred route");
13657  }
13658  AllRoutes->StoreOneRoute(1, this);
13659  AllRoutes->GetModifiableRouteAt(3, AllRoutes->AllRoutesSize() - 1).SetRoutePoints(1); // new addition
13660  AllRoutes->GetModifiableRouteAt(16, AllRoutes->AllRoutesSize() - 1).SetRouteSignals(5); // new addition
13661  if(!AutoSigsFlag)
13662  {
13663  AllRoutes->GetModifiableRouteAt(18, AllRoutes->AllRoutesSize() - 1).SetLCChangeValues(1, true); // ConsecSignalsRoute is true
13664  }
13665  AllRoutes->CheckMapAndRoutes(2); // test
13666  Utilities->CallLogPop(257);
13667 }
13668 
13669 // ---------------------------------------------------------------------------
13670 
13671 bool TOneRoute::GetNonPreferredRouteStartElement(int Caller, int HLoc, int VLoc, bool ConsecSignalsRoute, bool Callon) // Return true if OK.
13672 {
13673 /*
13674  [Note: original intention was to allow both consecutive signals and non-consecutive signals for routes
13675  on track with or without pref dirs set, hence the bool ConsecSignalsRoute, subsequently decided to
13676  make all unrestricted routes nonconsecutive signals, so that parameter will always be false. leave
13677  as is in case wish to change at a later time]
13678 
13679  If Callon true then called to set an unrestricted call-on route - suppress messages
13680  Clear the PrefDir and search vectors using ClearRoute(). Check selection matches a TrackElement
13681  & ensure signal/buffers/continuation.
13682  Note that can't select ConsecSignalsRoute for non-preferred routes.
13683  Check if train on element & disallow.
13684  Set default values for retained parameters:-
13685  StartRoutePosition = TrackVectorPosition of the element to be used as the start of the route;
13686  StartSelectionRouteID = route that selection starts in if there is one;
13687 
13688  Create 2 PrefDirElements from the TrackElement, setting all values corresponding to the 2 possible PrefDirs
13689  through the element (can only be 2 as 3 & 4 ended elements aren't allowed) & make an EXNumber check for
13690  validity. This is just for safety reasons, the PrefDir values aren't used.
13691  StartElement1 & 2 are set to these PrefDirelements.
13692 
13693  There is no need to check that the element lies in a PrefDir for nonpreferred selections.
13694 
13695  Check if in an existing route & if so only allow last element to be selected - ensure it has somewhere to go!
13696  Set StartElement1, StartSelectionRouteID and StartRoutePosition to correspond to the route end element and
13697  blank StartElement2 (only want to use the route element), then return true.
13698  Check if adjacent to start or end of an existing route & disallow if so.
13699  If not in a route and not failed so far then reset all Link, all LinkPos, & EXNumber values to -1, and CheckCount
13700  to 4 for StartElement1, & blank StartElement2. The remaining data members will be set later in
13701  SetRemainingSearchVectorValues().
13702  Finally add the required element to the SearchVector & return true.
13703 */
13704  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetNonPreferredRouteStartElement," + AnsiString(HLoc) + "," +
13705  AnsiString(VLoc) + "," + AnsiString((short)Callon));
13706  ClearRoute();
13707  int TrackVectorPosition;
13708  TTrackElement TrackElement;
13709  TPrefDirElement FirstElement, LastElement;
13710 
13711  if(!(Track->FindNonPlatformMatch(9, HLoc, VLoc, TrackVectorPosition, TrackElement)))
13712  {
13713  Utilities->CallLogPop(258);
13714  return false;
13715  }
13716  if((TrackElement.TrackType == Points) || (TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Crossover))
13717  {
13718  if(!Callon)
13719  TrainController->StopTTClockMessage(34, "Can't select points, bridge or crossover when route building");
13720 // makes later adjacent route checks too complicated
13721  Utilities->CallLogPop(259);
13722  return false;
13723  }
13724 
13725  if(Track->IsLCAtHV(21, HLoc, VLoc))
13726  {
13727  TrainController->StopTTClockMessage(74, "Can't start a route on a level crossing");
13728  Utilities->CallLogPop(1910);
13729  return false;
13730  }
13731 
13732 // check if selected a train & disallow if so
13733  if(TrackElement.TrainIDOnElement > -1)
13734  {
13735  if(!Callon)
13736  TrainController->StopTTClockMessage(35, "Can't start a route on a train");
13737  Utilities->CallLogPop(260);
13738  return false;
13739  }
13740 
13741 // check if selected a locked route element & disallow (can only be a 2-track element so only need check XLinkPos values of 0 & 1
13742  TPrefDirElement PrefDirElement;
13743  int LockedVectorNumber;
13744 
13745  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(3, TrackVectorPosition, 0, PrefDirElement, LockedVectorNumber))
13746  {
13747  if(!Callon)
13748  TrainController->StopTTClockMessage(36, "Can't start a route on a locked route");
13749  Utilities->CallLogPop(261);
13750  return false;
13751  }
13752  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(4, TrackVectorPosition, 1, PrefDirElement, LockedVectorNumber))
13753  {
13754  if(!Callon)
13755  TrainController->StopTTClockMessage(37, "Can't start a route on a locked route");
13756  Utilities->CallLogPop(262);
13757  return false;
13758  }
13759 
13761 // AdjacentStartRouteNumber = -1;
13762  StartRoutePosition = TrackVectorPosition;
13763 // StartRouteSelectPosition = TrackVectorPosition;
13764 
13765  TPrefDirElement PrefDirElement1(TrackElement); // 1 & 2 for the 2 possible PrefDirs at this location
13766  TPrefDirElement PrefDirElement2(TrackElement);
13767 
13768  PrefDirElement1.TrackVectorPosition = TrackVectorPosition;
13769  PrefDirElement2.TrackVectorPosition = TrackVectorPosition;
13770  TPrefDirElement BlankElement;
13771 
13772  PrefDirElement1.ELinkPos = 0;
13773  PrefDirElement1.XLinkPos = 1;
13774  PrefDirElement1.ELink = PrefDirElement1.Link[0];
13775  PrefDirElement1.XLink = PrefDirElement1.Link[1];
13776  if(!(PrefDirElement1.EntryExitNumber()))
13777  {
13778  throw Exception("Error, No EXNumber for PrefDirElement1 in GetNonPreferredRouteStartElement");
13779  // no need for bridge check as bridge selections not allowed
13780  }
13781  PrefDirElement1.CheckCount = 9;
13782  PrefDirElement2.ELinkPos = 1;
13783  PrefDirElement2.XLinkPos = 0;
13784  PrefDirElement2.ELink = PrefDirElement2.Link[1];
13785  PrefDirElement2.XLink = PrefDirElement2.Link[0];
13786  if(!(PrefDirElement2.EntryExitNumber()))
13787  {
13788  throw Exception("Error, No EXNumber for PrefDirElement2 in GetNonPreferredRouteStartElement");
13789  }
13790  PrefDirElement2.CheckCount = 9; // both now set
13791 
13792 // set StartElements to the above PrefDirElements
13793  StartElement1 = PrefDirElement1;
13794  StartElement2 = PrefDirElement2;
13795 
13796 // no PrefDir check needed as doesn't need to be in a PrefDir
13797 
13798 // look for exact match in a route first - can't be a 3 or 4 track element so only need to look for one TRouteElementPair
13800  TAllRoutes::TRouteElementPair RoutePair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(1, TrackElement.HLoc, TrackElement.VLoc, DummyPair);
13801 
13802  if(RoutePair.first > -1)
13803  {
13804  if(RoutePair.second != AllRoutes->GetFixedRouteAt(31, RoutePair.first).PrefDirSize() - 1) // not last element in existing route so no good
13805  {
13806  if(!Callon)
13807  TrainController->StopTTClockMessage(38, "Can't start a route within or at the start of an existing route");
13808  Utilities->CallLogPop(263);
13809  return false;
13810  }
13811  TPrefDirElement RouteElement = AllRoutes->GetFixedRouteAt(32, RoutePair.first).GetFixedPrefDirElementAt(56, RoutePair.second);
13812  if(RouteElement.Conn[RouteElement.XLinkPos] < 0) // last element in existing route but nowhere to go!
13813  {
13814  if(!Callon)
13815  TrainController->StopTTClockMessage(39, "No forward connection from this position");
13816  Utilities->CallLogPop(264);
13817  return false;
13818  }
13819  if((RouteElement.Config[RouteElement.XLinkPos] != End) && (AllRoutes->TrackIsInARoute(11, RouteElement.Conn[RouteElement.XLinkPos],
13820  RouteElement.ConnLinkPos[RouteElement.XLinkPos])))
13821  // last element in existing route but that route linked to another route (or a non-bridge 2-track element containing a route) so no good
13822  {
13823  if(!Callon)
13824  TrainController->StopTTClockMessage(40, "Can't start a route at an element that links forward into an existing route");
13825  Utilities->CallLogPop(265);
13826  return false;
13827  }
13828  StartSelectionRouteID = IDInt(AllRoutes->GetFixedRouteAt(162, RoutePair.first).RouteID);
13830  AllRoutes->GetFixedRouteAt(34, RoutePair.first).PrefDirSize() - 1); // last element
13831  StartElement2 = BlankElement; // only use the route element
13833  Utilities->CallLogPop(266);
13834  return true; // all retained values set
13835  }
13836 
13837  else // selection not in an existing route
13838  {
13839 // check if it's adjacent to start of an an existing route,
13840  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
13841  {
13842  FirstElement = AllRoutes->GetFixedRouteAt(35, a).GetFixedPrefDirElementAt(58, 0);
13843  if((StartElement1.Conn[0] > -1) && (StartElement1.Conn[0] == FirstElement.TrackVectorPosition))
13844  {
13845  if(!Callon)
13846  TrainController->StopTTClockMessage(41, "Can't make selection adjacent to start of another route");
13847  Utilities->CallLogPop(267);
13848  return false;
13849  }
13850  if((StartElement1.Conn[1] > -1) && (StartElement1.Conn[1] == FirstElement.TrackVectorPosition))
13851  {
13852  if(!Callon)
13853  TrainController->StopTTClockMessage(42, "Can't make selection adjacent to start of another route");
13854  Utilities->CallLogPop(268);
13855  return false;
13856  }
13857  }
13858 // check if it's adjacent to end of an an existing route,
13859  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
13860  {
13862  if(LastElement.Conn[LastElement.XLinkPos] == StartRoutePosition)
13863  {
13864  if(!Callon)
13865  TrainController->StopTTClockMessage(43, "Can't start a route adjacent to the end of an existing route");
13866  Utilities->CallLogPop(269);
13867  return false;
13868  }
13869  }
13870  // not in a route or adjacent to start or end of a route
13871  // in this case reset all variable values to -1 & CheckCount to 4
13872  StartElement1.ELink = -1;
13873  StartElement1.ELinkPos = -1;
13874  StartElement1.XLink = -1;
13875  StartElement1.XLinkPos = -1;
13876  StartElement1.EXNumber = -1;
13878  StartElement2 = BlankElement;
13879  SearchVector.push_back(StartElement1);
13880  Utilities->CallLogPop(270);
13881  return true;
13882  }
13883 }
13884 
13885 // ---------------------------------------------------------------------------
13886 bool TOneRoute::GetNextNonPreferredRouteElement(int Caller, int HLoc, int VLoc, bool ConsecSignalsRoute, bool Callon, IDInt &ReqPosRouteID, bool &PointsChanged)
13887 
13888 /*
13889  If Callon true then called to set an unrestricted call-on route - suppress messages & allow points to be selected
13890 
13891  Declare the following integers:-
13892  EndPosition - TrackVectorPosition for the selection;
13893  ReqPosRouteID - for the existing route selected, set to -1 if not used and initially;
13894  Check if selection is a valid track element and set EndPosition.
13895  Cancel if select original start element, then check that not points, bridge or crossover.
13896  Check & fail if a train is present at the selection.
13897  Create & set 2 PrefDirElements EndElement1 & 2 corresponding to the 2 possible PrefDir elements (similar to StartElement1 & 2
13898  in GetNonPreferredRouteStartElement) & make an EXNumber validity check just for safety reasons - the PrefDir values are not used.
13899  No check needed for selection in EveryPrefDir.
13900  Check if selection in an existing route & if so ensure it's the start element and that it doesn't have an 'End' facing the start.
13901  If it is the start of a route set ReqPosRouteID, EndPosition & EndElement1 to the start of route values and blank EndElement2
13902  as don't need it if in a route.
13903  Check if selection adj to start or end of a route and disallow.
13904  Fail if select same route as starting route, though should already have failed earlier if this is so.
13905 
13906  If there's a StartSelectionRouteID then StartElement1 will be set to
13907  the last entry in the selected route so use SearchForNonPreferredRoute to search for the selected end element from this
13908  start element. If succeed then complete the search vector values (since not on a PrefDir) & return true, for Interface
13909  to handle the flashing & time delay. After the delay completes the Interface flasher calls ConvertAndAddNonPreferredRouteSearchVector
13910  to add the new route to the AllRoutesVectorPtr.
13911  If no starting route then StartElement1 only has basic values set & is in the SearchVector, and StartElement2 is blank.
13912  Check if the selected element is adjacent to the starting position and if so set the route to go directly to it (as opposed to
13913  going round a long loop to get to it just because that XLinkPos happens to be chosen first).
13914  If not adjacent then search on the two possible ways out of StartElement1 providing it isn't facing an 'End'. If succeed complete
13915  the search vector values and return.
13916  If not returned yet then have failed to find the required element so return false with no message.
13917 */
13918 
13919 {
13920 // get EndPosition
13921  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetNextNonPreferredRouteElement," + AnsiString(HLoc) + "," +
13922  AnsiString(VLoc));
13923  int EndPosition;
13924 
13925  TotalSearchCount = 0;
13926  ReqPosRouteID = IDInt(-1); // for not used
13927  TTrackElement TrackElement;
13928  TPrefDirElement BlankElement;
13929 
13930  if(!(Track->FindNonPlatformMatch(10, HLoc, VLoc, EndPosition, TrackElement))) // return if can't find one
13931  {
13932  Utilities->CallLogPop(271);
13933  return false;
13934  }
13935 // EndPosition = EndSelectPosition;
13936 // cancel selection if on original start element
13937  if(EndPosition == StartRoutePosition)
13938  {
13939  Utilities->CallLogPop(272);
13940  return false;
13941  }
13942 
13943  if(Track->IsLCAtHV(22, HLoc, VLoc))
13944  {
13945  TrainController->StopTTClockMessage(75, "Can't end a route on a level crossing");
13946  Utilities->CallLogPop(1911);
13947  return false;
13948  }
13949 
13950  if((TrackElement.TrackType == Points) && !Callon)
13951  {
13952  if(!Callon)
13953  TrainController->StopTTClockMessage(44, "Can't select points, bridge or crossover when route building");
13954 // makes later adjacent route checks too complicated
13955  Utilities->CallLogPop(273);
13956  return false;
13957  }
13958 
13959  if((TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Crossover))
13960  {
13961  if(!Callon)
13962  TrainController->StopTTClockMessage(71, "Can't select points, bridge or crossover when route building");
13963 // makes later adjacent route checks too complicated
13964  Utilities->CallLogPop(1861);
13965  return false;
13966  }
13967 
13968 // check if train on element
13969  if(TrackElement.TrainIDOnElement > -1)
13970  {
13971  if(!Callon)
13972  TrainController->StopTTClockMessage(45, "Can't end a route on a train");
13973  Utilities->CallLogPop(274);
13974  return false;
13975  }
13976 
13977 // set the 2 EndElements corresponding to the 2 possible PrefDirs for the selected element (for safety reasons - to ensure EXNumber validity
13978 // check passed)
13979  TPrefDirElement EndElement1(TrackElement); // 1 & 2 for the 2 possible PrefDirs at this location
13980  TPrefDirElement EndElement2(TrackElement);
13981 
13982  EndElement1.TrackVectorPosition = EndPosition;
13983  EndElement2.TrackVectorPosition = EndPosition;
13984  EndElement1.ELinkPos = 0;
13985  EndElement1.XLinkPos = 1;
13986  EndElement1.ELink = EndElement1.Link[0];
13987  EndElement1.XLink = EndElement1.Link[1];
13988  if(!(EndElement1.EntryExitNumber()))
13989  {
13990  throw Exception("Error, No EXNumber for EndElement1 in GetNonPreferredRouteStartElement");
13991  }
13992  EndElement1.CheckCount = 9;
13993  EndElement2.ELinkPos = 1;
13994  EndElement2.XLinkPos = 0;
13995  EndElement2.ELink = EndElement2.Link[1];
13996  EndElement2.XLink = EndElement2.Link[0];
13997  if(!(EndElement2.EntryExitNumber()))
13998  {
13999  throw Exception("Error, No EXNumber for EndElement2 in GetNonPreferredRouteStartElement");
14000  }
14001  EndElement2.CheckCount = 9; // both now set
14002 
14003 // set the H&V limits for the search, all points on search path must lie within 15 elements greater than the box of which the line between
14004 // start and finish is a diagonal line [dropped as not a good strategy because gaps interfered with direct line searches - instead
14005 // introduced TotalSearchCount and now use that to limit searches. Leave in though in case rethink strategy later on]
14006 
14007  if(EndElement1.HLoc >= StartElement1.HLoc)
14008  {
14010  SearchLimitHighH = EndElement1.HLoc + 15;
14011  }
14012  else
14013  {
14014  SearchLimitLowH = EndElement1.HLoc - 15;
14016  }
14017 
14018  if(EndElement1.VLoc >= StartElement1.VLoc)
14019  {
14021  SearchLimitHighV = EndElement1.VLoc + 15;
14022  }
14023  else
14024  {
14025  SearchLimitLowV = EndElement1.VLoc - 15;
14027  }
14028 
14029 /* dropped this for v0.4d - prevents ability to set routes for gaps that are widely separated, ok without it as search limited by SearchVector size
14030  check & TotalSearchCounts check
14031  if((abs(EndElement1.HLoc - StartElement1.HLoc) > 120) || (abs(EndElement1.VLoc - StartElement1.VLoc) > 120))
14032  {
14033  if(!Callon) TrainController->StopTTClockMessage(66, "Unable to reach the selected element - too far ahead");
14034  Utilities->CallLogPop(1694);
14035  return false;
14036  }
14037 */
14038 // don't need EveryPrefDir check for NonPreferredRoute
14039 
14040 // check if in an existing route - can't be a 3 or 4 track element so only one TRouteElementPair to be set
14041 // bool InRoute = false;
14043  TAllRoutes::TRouteElementPair RoutePair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(2, TrackElement.HLoc, TrackElement.VLoc, DummyPair);
14044 
14045  if(RoutePair.first > -1)
14046  {
14047  if(RoutePair.second != 0) // not first element in existing route so no good
14048  {
14049  if(!Callon)
14050  TrainController->StopTTClockMessage(46, "Can't end a route within or at the end of an existing route");
14051  Utilities->CallLogPop(275);
14052  return false;
14053  }
14054  TPrefDirElement RouteElement = AllRoutes->GetFixedRouteAt(38, RoutePair.first).GetFixedPrefDirElementAt(60, RoutePair.second);
14055 // if((RouteElement.Config[RouteElement.ELinkPos] != End) && (AllRoutes->TrackIsInARoute(, RouteElement.Conn[RouteElement.ELinkPos], RouteElement.ELinkPos)))
14056  if((RouteElement.Config[RouteElement.ELinkPos] != End) && (AllRoutes->TrackIsInARoute(12, RouteElement.Conn[RouteElement.ELinkPos],
14057  RouteElement.ConnLinkPos[RouteElement.ELinkPos]))) // amended at v1.3.0 - had omitted ConnLinkPos - see above
14058  // first element in existing route but that route linked to another route (or a non-bridge 2-track element containing a route) so no good
14059  {
14060  if(!Callon)
14061  TrainController->StopTTClockMessage(47, "Can't start a route within or at the end of an existing route");
14062  Utilities->CallLogPop(276);
14063  return false;
14064  }
14065  EndElement1 = AllRoutes->GetFixedRouteAt(39, RoutePair.first).GetFixedPrefDirElementAt(61, 0);
14066  EndElement2 = BlankElement; // only need the route element
14067  EndPosition = EndElement1.TrackVectorPosition;
14068  ReqPosRouteID = IDInt(AllRoutes->GetFixedRouteAt(161, RoutePair.first).RouteID);
14069  }
14070 
14071 // check if adjacent to start of an existing route and disallow (unless start of existing route is also the start of this route)
14072  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
14073  {
14074  int AdjPosition = AllRoutes->GetFixedRouteAt(40, a).GetFixedPrefDirElementAt(62, 0).TrackVectorPosition;
14075  int AdjLinkPos = AllRoutes->GetFixedRouteAt(219, a).GetFixedPrefDirElementAt(245, 0).ELinkPos; // added at v1.3.1
14076 // if((EndElement1.Config[EndElement1.XLinkPos] != End) && (EndElement1.Conn[EndElement1.XLinkPos] == AdjPosition)
14077 // && (AdjPosition != StartRoutePosition))
14078  if((EndElement1.Config[EndElement1.XLinkPos] != End) && (EndElement1.Conn[EndElement1.XLinkPos] == AdjPosition)
14079  && // changed at v1.3.1 to allow a route end adjacent to an element with a route that doesn't link to the ending route
14080  (EndElement1.ConnLinkPos[EndElement1.XLinkPos] == AdjLinkPos) && (AdjPosition != StartRoutePosition))
14081  {
14082  if(!Callon)
14083  TrainController->StopTTClockMessage(48, "Can't end a route adjacent to the start of an existing route");
14084  Utilities->CallLogPop(277);
14085  return false;
14086  }
14087 // else if((EndElement2.TrackVectorPosition > -1) && (EndElement2.Config[EndElement2.XLinkPos] != End) &&
14088 // (EndElement2.Conn[EndElement2.XLinkPos] == AdjPosition) && (AdjPosition != StartRoutePosition))
14089  else if((EndElement2.TrackVectorPosition > -1) && (EndElement2.Config[EndElement2.XLinkPos] != End)
14090  && // changed at v1.3.1 to allow a route end adjacent to an element with a route that doesn't link to the ending route
14091  (EndElement2.Conn[EndElement2.XLinkPos] == AdjPosition) && (EndElement2.ConnLinkPos[EndElement2.XLinkPos] == AdjLinkPos) &&
14092  (AdjPosition != StartRoutePosition))
14093  {
14094  if(!Callon)
14095  TrainController->StopTTClockMessage(49, "Can't end a route adjacent to the start of an existing route");
14096  Utilities->CallLogPop(278);
14097  return false;
14098  }
14099 
14100 // check if adjacent to end of a route & disallow (unless end of existing route is the start of this route - i.e. extending route by 1 element)
14102  if((EndOfRouteElement.Config[EndOfRouteElement.XLinkPos] != End) && (EndOfRouteElement.Conn[EndOfRouteElement.XLinkPos] == EndPosition) &&
14103  (EndOfRouteElement.TrackVectorPosition != StartRoutePosition))
14104  {
14105  if(!Callon)
14106  TrainController->StopTTClockMessage(50, "Can't end a route adjacent to the end of an existing route");
14107  Utilities->CallLogPop(279);
14108  return false;
14109  }
14110  }
14111 
14112 // check for same route as start element
14114  {
14115  if(!Callon)
14116  TrainController->StopTTClockMessage(51, "Can't select same route as started in");
14117  Utilities->CallLogPop(280);
14118  return false;
14119  }
14120 
14121 // check for a looping route
14122  if((ReqPosRouteID > -1) && (StartSelectionRouteID > -1))
14123  {
14125  {
14126  if(!Callon)
14127  TrainController->StopTTClockMessage(70, "Can't create a route that loops back on itself");
14128  Utilities->CallLogPop(1845);
14129  return false;
14130  }
14131  }
14132 
14133 // if there's a StartSelectionRouteID StartElement1 will be set to the last entry in the selected route
14134 // so search from this element.
14135 
14136  TTrackElement &TempElement1 = StartElement1; // this needed to avoid a TTrackElement construction ambiguity in later search function
14137 
14138  if(StartSelectionRouteID > -1)
14139  {
14140  if(SearchForNonPreferredRoute(0, TempElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID))
14141  {
14143  if(PointsToBeChanged(0))
14144  {
14145  PointsChanged = true;
14146  }
14147  Utilities->CallLogPop(281);
14148  return true;
14149  }
14150  else
14151  {
14152  if(!Callon)
14154  Utilities->CallLogPop(282);
14155  return false;
14156  }
14157  }
14158  else // no starting route, so StartElement1 only has basic values set & is in SearchVector, StartElement2 is blank
14159  // search on the 2 ways out of the element, which has to be a 2-ended element
14160  {
14161 // check if selection adjacent to start element and if so use that
14162  if(SearchVector.at(0).Conn[0] == EndPosition)
14163  {
14164  if(SearchForNonPreferredRoute(1, TempElement1, 0, EndPosition, ReqPosRouteID))
14165  {
14167  if(PointsToBeChanged(1))
14168  {
14169  PointsChanged = true;
14170  }
14171  Utilities->CallLogPop(283);
14172  return true;
14173  }
14174  else
14175  {
14176  if(!Callon)
14178  Utilities->CallLogPop(284);
14179  return false;
14180  }
14181  }
14182  else if(SearchVector.at(0).Conn[1] == EndPosition)
14183  {
14184  if(SearchForNonPreferredRoute(2, TempElement1, 1, EndPosition, ReqPosRouteID))
14185  {
14187  if(PointsToBeChanged(2))
14188  {
14189  PointsChanged = true;
14190  }
14191  Utilities->CallLogPop(285);
14192  return true;
14193  }
14194  else
14195  {
14196  if(!Callon)
14198  Utilities->CallLogPop(286);
14199  return false;
14200  }
14201  }
14202  // now start off in the best direction
14203  int BestPos = Track->FindClosestLinkPosition(1, StartRoutePosition, EndPosition); // can only be 0 or 1
14204 
14205  if(SearchVector.at(0).Config[BestPos] != End)
14206  {
14207  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
14208  if(SearchForNonPreferredRoute(3, TempElement1, BestPos, EndPosition, ReqPosRouteID))
14209  {
14211  if(PointsToBeChanged(3))
14212  {
14213  PointsChanged = true;
14214  }
14215  Utilities->CallLogPop(287);
14216  return true;
14217  }
14218  }
14219  if(SearchVector.at(0).Config[1 - BestPos] != End)
14220  {
14221  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
14222  if(SearchForNonPreferredRoute(4, TempElement1, (1 - BestPos), EndPosition, ReqPosRouteID))
14223  {
14225  if(PointsToBeChanged(4))
14226  {
14227  PointsChanged = true;
14228  }
14229  Utilities->CallLogPop(288);
14230  return true;
14231  }
14232  }
14233  }
14234  if(!Callon)
14236  Utilities->CallLogPop(289);
14237  return false;
14238 }
14239 
14240 // ---------------------------------------------------------------------------
14241 
14242 bool TOneRoute::SearchForNonPreferredRoute(int Caller, TTrackElement CurrentTrackElement, int XLinkPos, int RequiredPosition, IDInt ReqPosRouteID)
14243 /*
14244  This is very similar to the preferred route search, but without the need to ensure all elements are in EveryPrefDir.
14245  Returns true for successful search with SearchVector containing the new route elements. Enter with CurrentTrackElement
14246  stored in SearchVector unless it's in an existing route, & XLinkPos set to the link to search on.
14247  Keep a count of entries in SearchVector during the current function call, so that this number can be
14248  erased for an unproductive branch search.
14249  First check (within the loop) whether XLink leads to an End & return false if so.
14250  Create a NextTrackElement from Current & XLinkPos, and a PrefDirElement (SearchElement) from that, setting as many values as
14251  possible. Check if element is already in searchvector (OK if a bridge & earlier entry on different track, but not OK if
14252  any other type of element), already in an existing route (OK if bridge & diff tracks, or start of an expected route), if
14253  train on element (unless a bridge & train on different track), or if element
14254  fouls an existing diagonal route (except if element is a leading point - these checked later).
14255  Then check if found required element. If so save it & return true.
14256  If not the required element check if buffer or continuation, & if so erase all searchvector
14257  & return false. If OK check if a leading point and if so do up to 2 recursive searches for the 2 exits (trying the 'set' exit first),
14258  checking in each case whether the element fouls an existing diagonal route. If fail on both exits erase searchvector & return false.
14259  If not any of above, store element in SearchVector, increment VectorCount, set the new CurrentTrackElement value from the
14260  SearchElement & the new XLinkPos from SearchElement.XLinkPos, then go back to the while loop for the next step in the search.
14261  When return true have 8 items from CheckCount established, only waiting for EXNumber
14262 */
14263 {
14264  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchForNonPreferredRoute," + CurrentTrackElement.LogTrack(14) + "," +
14265  AnsiString(XLinkPos) + "," + AnsiString(RequiredPosition) + "," + AnsiString() + "," + AnsiString(ReqPosRouteID.GetInt()));
14266  int VectorCount = 0;
14267 
14268 // check for a fouled diagonal for first element. Added for v1.3.2
14269  if((CurrentTrackElement.Link[XLinkPos] == 1) || (CurrentTrackElement.Link[XLinkPos] == 3) || (CurrentTrackElement.Link[XLinkPos] == 7) ||
14270  (CurrentTrackElement.Link[XLinkPos] == 9))
14271  {
14272  if(AllRoutes->DiagonalFouledByRouteOrTrain(8, CurrentTrackElement.HLoc, CurrentTrackElement.VLoc, CurrentTrackElement.Link[XLinkPos]))
14273  {
14274  for(int x = 0; x < VectorCount; x++)
14275  SearchVector.erase(SearchVector.end() - 1);
14276  Utilities->CallLogPop(2044);
14277  return false;
14278  }
14279  }
14280 
14281  while(true)
14282  {
14283  if(Track->IsLCBarrierFlashingAtHV(2, CurrentTrackElement.HLoc, CurrentTrackElement.VLoc)) // can't set a route through a flashing barrier
14284  {
14285  for(int x = 0; x < VectorCount; x++)
14286  SearchVector.erase(SearchVector.end() - 1);
14287  Utilities->CallLogPop(1927);
14288  return false;
14289  }
14290  if(CurrentTrackElement.Config[XLinkPos] == End) // buffers or continuation
14291  {
14292  for(int x = 0; x < VectorCount; x++)
14293  SearchVector.erase(SearchVector.end() - 1);
14294  Utilities->CallLogPop(290);
14295  return false;
14296  }
14297  int NextPosition = CurrentTrackElement.Conn[XLinkPos];
14298  TTrackElement NextTrackElement = Track->TrackElementAt(93, NextPosition);
14299  TPrefDirElement SearchElement(NextTrackElement);
14300  SearchElement.TrackVectorPosition = NextPosition;
14301  int NextELinkPos = CurrentTrackElement.ConnLinkPos[XLinkPos];
14302  SearchElement.ELinkPos = NextELinkPos;
14303  SearchElement.ELink = SearchElement.Link[SearchElement.ELinkPos];
14304  int NextXLinkPos;
14305  if(SearchElement.ELinkPos == 0)
14306  NextXLinkPos = 1;
14307  if(SearchElement.ELinkPos == 1)
14308  NextXLinkPos = 0;
14309  if(SearchElement.ELinkPos == 2)
14310  NextXLinkPos = 3;
14311  if(SearchElement.ELinkPos == 3)
14312  NextXLinkPos = 2;
14313  if((SearchElement.TrackType != Points) || (SearchElement.Config[SearchElement.ELinkPos] != Lead))
14314  {
14315  SearchElement.XLink = SearchElement.Link[NextXLinkPos];
14316  // but may be buffers, continuation or gap
14317  SearchElement.XLinkPos = NextXLinkPos;
14318  }
14319 // Now have SpeedTag, HLoc, VLoc, TrackVectorPosition, ELink, ELinkPos, and for non-points XLink & XLinkPos
14320 // can't set XLink or XLinkPos yet if the element is a leading point.
14321 
14322 // check if reached an earlier position on search PrefDir (was OK in SearchForPrefDir if entry values different, but not OK for a route)
14323  for(unsigned int x = 0; x < SearchVector.size(); x++)
14324  {
14325  if(SearchElement.TrackVectorPosition == SearchVector.at(x).TrackVectorPosition)
14326  {
14327  if((SearchElement.TrackType != Bridge) || ((SearchElement.TrackType == Bridge) && (SearchElement.ELink == SearchVector.at(x).ELink)))
14328  // OK if it's a bridge & routes on different tracks
14329  {
14330  for(int x = 0; x < VectorCount; x++)
14331  SearchVector.erase(SearchVector.end() - 1);
14332  Utilities->CallLogPop(291);
14333  return false;
14334  }
14335  }
14336  }
14337 
14338 // check if element in an existing route (OK if bridge & diff tracks, or start of an expected route)
14339  TAllRoutes::TRouteElementPair SecondPair;
14341  Track->TrackElementAt(94, SearchElement.TrackVectorPosition).HLoc, Track->TrackElementAt(95, SearchElement.TrackVectorPosition).VLoc, SecondPair);
14342  if(RoutePair.first > -1)
14343  {
14344  // OK if it's a bridge & routes on different tracks (hard to see how can reach a bridge before another element in route as can't start on a bridge, but leave check in anyway)
14345  if(!((SearchElement.TrackType == Bridge) && (SearchElement.ELinkPos != AllRoutes->GetFixedRouteAt(43, RoutePair.first).GetFixedPrefDirElementAt(64,
14346  RoutePair.second).ELinkPos)))
14347  {
14348  // still OK if start of an expected route
14349  if((ReqPosRouteID == IDInt(-1)) || ((int)RoutePair.first != AllRoutes->GetRouteVectorNumber(4, ReqPosRouteID)) || (RoutePair.second != 0))
14350  {
14351  for(int x = 0; x < VectorCount; x++)
14352  SearchVector.erase(SearchVector.end() - 1);
14353  Utilities->CallLogPop(292);
14354  return false; // only allow for start of an expected route
14355  }
14356  }
14357  }
14358  if(SecondPair.first > -1) // if reach here & secondpair present then must fail as can't escape both existing routes, but leave check as before anyway
14359  {
14360  // OK if it's a bridge & routes on different tracks
14361  if(!((SearchElement.TrackType == Bridge) && (SearchElement.ELinkPos != AllRoutes->GetFixedRouteAt(44, SecondPair.first).GetFixedPrefDirElementAt(65,
14362  SecondPair.second).ELinkPos)))
14363  {
14364  // still OK if start of an expected route
14365  if((ReqPosRouteID == IDInt(-1)) || ((int)SecondPair.first != AllRoutes->GetRouteVectorNumber(5, ReqPosRouteID)) || (SecondPair.second != 0))
14366  {
14367  for(int x = 0; x < VectorCount; x++)
14368  SearchVector.erase(SearchVector.end() - 1);
14369  Utilities->CallLogPop(293);
14370  return false; // only allow for start of an expected route
14371  }
14372  }
14373  }
14374 
14375 // check if a train on element, unless a bridge & train on different track
14376 // OK of same train as start element - no, drop this
14377 // if(SearchElement.TrainIDOnElement != StartSelectionTrainID)
14378  if((SearchElement.TrainIDOnElement > -1) && (SearchElement.TrackType != Bridge))
14379  {
14380  for(int x = 0; x < VectorCount; x++)
14381  SearchVector.erase(SearchVector.end() - 1);
14382  Utilities->CallLogPop(294);
14383  return false;
14384  }
14385  if((SearchElement.TrainIDOnElement > -1) && (SearchElement.TrackType == Bridge))
14386  {
14387  if((SearchElement.ELinkPos < 2) && (SearchElement.TrainIDOnBridgeTrackPos01 > -1))
14388  {
14389  for(int x = 0; x < VectorCount; x++)
14390  SearchVector.erase(SearchVector.end() - 1);
14391  Utilities->CallLogPop(295);
14392  return false;
14393  }
14394  else if((SearchElement.ELinkPos > 1) && (SearchElement.TrainIDOnBridgeTrackPos23 > -1))
14395  {
14396  for(int x = 0; x < VectorCount; x++)
14397  SearchVector.erase(SearchVector.end() - 1);
14398  Utilities->CallLogPop(296);
14399  return false;
14400  }
14401  }
14402 
14403 // check for a fouled diagonal (if not leading point - leading point XLink == -1)
14404  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
14405  {
14406  if(AllRoutes->DiagonalFouledByRouteOrTrain(3, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
14407  {
14408  for(int x = 0; x < VectorCount; x++)
14409  SearchVector.erase(SearchVector.end() - 1);
14410  Utilities->CallLogPop(297);
14411  return false;
14412  }
14413  }
14414 
14415 // check if exceeds the search H & V limits - drop in favour of limiting TotalSearchCount
14416 // if((SearchElement.HLoc > SearchLimitHighH) || (SearchElement.HLoc < SearchLimitLowH) ||
14417 // (SearchElement.VLoc > SearchLimitHighV) ||(SearchElement.VLoc < SearchLimitLowV))
14419  {
14420  for(int x = 0; x < VectorCount; x++)
14421  SearchVector.erase(SearchVector.end() - 1);
14422  Utilities->CallLogPop(1689);
14423  return false;
14424  }
14425 
14426 // check if found it
14427  if(SearchElement.TrackVectorPosition == RequiredPosition)
14428  {
14429  if(SearchElement.TrackType == Points) // can only happen for platform element in CallingOnAllowed function
14430  {
14431  if((SearchElement.ELinkPos == 1) || (SearchElement.ELinkPos == 3))
14432  SearchElement.XLinkPos = 0; // select the straight track (for the platform)
14433  else
14434  SearchElement.XLinkPos = 1;
14435 // SearchElement.XLink = SearchElement.Link[XLinkPos]; WRONG!! NajamUddin found this error 17/01/11, XLinkPos is the function input parameter, should be SearchElement.XLinkPos
14436  SearchElement.XLink = SearchElement.Link[SearchElement.XLinkPos]; // corrected for v0.6a
14437  }
14438  SearchVector.push_back(SearchElement);
14439  VectorCount++; // not really needed but include for tidyness
14440  TotalSearchCount++;
14441  Utilities->CallLogPop(298);
14442  return true;
14443  }
14444 // Not the required element - check if a buffer or continuation
14445  if((SearchElement.TrackType == Buffers) || (SearchElement.TrackType == Continuation))
14446  {
14447  for(int x = 0; x < VectorCount; x++)
14448  SearchVector.erase(SearchVector.end() - 1);
14449  Utilities->CallLogPop(299);
14450  return false;
14451  }
14452 
14453 // check if SearchVector exceeds a size of 150
14454  if(SearchVector.size() > 150)
14455  {
14456  for(int x = 0; x < VectorCount; x++)
14457  SearchVector.erase(SearchVector.end() - 1);
14458  Utilities->CallLogPop(1421);
14459  return false;
14460  }
14461 
14462 // check if reached a leading point
14463  if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Lead))
14464  {
14465 // XLink set to points 'set' position - Attribute == 0, SearchPos1 = 1 & SearchPos2 = 3; Attribute == 1, SearchPos1 = 3 & SearchPos2 = 1;
14466  int SearchPos1 = SearchElement.Attribute + 1;
14467  int SearchPos2;
14468  if(SearchPos1 == 2)
14469  SearchPos1++;
14470  if(SearchPos1 == 1)
14471  SearchPos2 = 3;
14472  else
14473  SearchPos2 = 1;
14474 // push element with XLink set to position [SearchPos1]
14475  SearchElement.XLink = SearchElement.Link[SearchPos1];
14476  SearchElement.XLinkPos = SearchPos1;
14477 // check for a fouled diagonal for leading point for XLinkPos == SearchPos1)
14478  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
14479  {
14480  if(AllRoutes->DiagonalFouledByRouteOrTrain(4, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
14481  {
14482  for(int x = 0; x < VectorCount; x++)
14483  SearchVector.erase(SearchVector.end() - 1);
14484  Utilities->CallLogPop(300);
14485  return false;
14486  }
14487  }
14488  SearchVector.push_back(SearchElement);
14489  VectorCount++;
14490  TotalSearchCount++;
14491 // recursive search at XLinkPos of SearchPos1 (i.e. 'set' trailing exit)
14492 // Note that NextTrackElement is the TTrackElement that the TPrefDirElement SearchElement is constructed from. Can't use SearchElement in the
14493 // recursive search as has to be a TTrackElement for non-preferred route searches
14494  if(SearchForNonPreferredRoute(6, NextTrackElement, SearchPos1, RequiredPosition, ReqPosRouteID))
14495  {
14496  Utilities->CallLogPop(301);
14497  return true;
14498  }
14499  else
14500  {
14501 // remove leading point with XLinkPos [SearchPos1]
14502  SearchVector.erase(SearchVector.end() - 1);
14503  VectorCount--;
14504 // push element with XLink set to position [SearchPos2]
14505  SearchElement.XLink = SearchElement.Link[SearchPos2];
14506  SearchElement.XLinkPos = SearchPos2;
14507 // check for a fouled diagonal for leading point for XLinkPos == SearchPos2)
14508  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
14509  {
14510  if(AllRoutes->DiagonalFouledByRouteOrTrain(5, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
14511  {
14512  for(int x = 0; x < VectorCount; x++)
14513  SearchVector.erase(SearchVector.end() - 1);
14514  Utilities->CallLogPop(302);
14515  return false;
14516  }
14517  }
14518  SearchVector.push_back(SearchElement);
14519  VectorCount++;
14520  TotalSearchCount++;
14521 // recursive search at XLinkPos of SearchPos2 (i.e. 'unset' trailing exit)
14522  if(SearchForNonPreferredRoute(7, NextTrackElement, SearchPos2, RequiredPosition, ReqPosRouteID))
14523  {
14524  Utilities->CallLogPop(303);
14525  return true;
14526  }
14527  else
14528  {
14529  for(int x = 0; x < VectorCount; x++)
14530  SearchVector.erase(SearchVector.end() - 1);
14531  Utilities->CallLogPop(304);
14532  return false;
14533  }
14534  }
14535  } // if leading point
14536 // here if ordinary element, push it, inc VectorCount & update CurrentTrackElement
14537 // ready for next element on route
14538  SearchVector.push_back(SearchElement);
14539  VectorCount++;
14540  TotalSearchCount++;
14541  CurrentTrackElement = SearchElement;
14542  XLinkPos = SearchElement.XLinkPos; // wasn't a leading point so XLinkPos defined
14543  } // while(true)
14544 }
14545 
14546 // ---------------------------------------------------------------------------
14547 
14549 
14550 /*
14551  This function is developed from ConvertPrefDirSearchVector, to deal with search elements not
14552  having all values set (since not necessarily on PrefDirs).
14553  Enter with SearchVector established, return if empty. The first element may not have its ELink & XLink etc set
14554  (if it was the start), so these are checked first and set if necessary. All elements now have
14555  all but EXNumber set, so the CheckCount is set to 8 to cover all but EXNumber, and that is then set
14556  for all elements (unless validity check fails) and CheckCount incremented. Finally SetRouteSearchVectorGraphics() is called
14557  to set the route colour and direction graphics.
14558 */
14559 
14560 {
14561  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRemainingSearchVectorValues");
14562  if(SearchVector.size() == 0)
14563  {
14564  throw Exception("Error, SearchVector empty");
14565  }
14566 // first SearchElement may have ELink & XLink not set if entered in GetStart.... i.e if it wasn't already in a route
14567 // hence need to examine and update it if necessary
14568  TPrefDirElement SecondElement;
14569 
14570  if(SearchVector.size() > 1) // if search vector only a single element then first element must have been in a route, and in this case
14571  // all data members will have been set in SearchForNonPreferredRoute except for EXNumber.
14572  // need above check or SecondElement will fail
14573  {
14574  SecondElement = SearchVector.at(1);
14575  // SearchVector.at(0) ELink & XLink not set if was first element in route; XLink also not set if was a leading point though can't be for a route
14576  for(int x = 0; x < 4; x++)
14577  {
14578  if(SearchVector.at(0).Conn[x] == SecondElement.TrackVectorPosition)
14579  {
14580  if(SearchVector.at(0).XLink == -1) // i.e. not set
14581  {
14582  SearchVector.at(0).XLink = SearchVector.at(0).Link[x];
14583  SearchVector.at(0).XLinkPos = x;
14584  }
14585  int ELinkPos;
14586  if(SearchVector.at(0).XLinkPos == 0)
14587  ELinkPos = 1; // use actual value rather than 'x' as may be a gap with both ends
14588  // linked to 1st searchvector element, & if XLink was set then x may not correspond
14589  if(SearchVector.at(0).XLinkPos == 1)
14590  ELinkPos = 0;
14591  if(SearchVector.at(0).XLinkPos == 2)
14592  ELinkPos = 3;
14593  if(SearchVector.at(0).XLinkPos == 3)
14594  ELinkPos = 2;
14595  if(SearchVector.at(0).ELink == -1) // because was start element, & can't be points, but could be a gap
14596  {
14597  SearchVector.at(0).ELink = SearchVector.at(0).Link[ELinkPos];
14598  SearchVector.at(0).ELinkPos = ELinkPos;
14599  }
14600  break; // no point going any further
14601  }
14602  }
14603  }
14604  for(unsigned int x = 0; x < SearchVector.size(); x++)
14605  {
14606  SearchVector.at(x).CheckCount = 8; // to account for all but EXNumber
14607 // set EXNumber
14608  if(!(SearchVector.at(x).EntryExitNumber()))
14609  {
14610  throw Exception("Error in EntryExitNumber 3");
14611  }
14612  SearchVector.at(x).CheckCount++;
14613 // all values now incorporated
14614  }
14615 
14616  SetRouteSearchVectorGraphics(5, false, false); // change graphic colour to the route colour
14617 // This function is only called here for nonsignals routes, so AutoSigsFlag & ConsecSignalsRoute both false
14618 // PrefDir is validated in ConvertAndAddNonPreferredRouteSearchVector
14619  Utilities->CallLogPop(305);
14620 }
14621 
14622 // ---------------------------------------------------------------------------
14623 
14625 
14626 /*
14627  This function is very similar to ConvertAndAddPreferredRouteSearchVector except that the route in SearchVector can't be an
14628  AutoSigsRoute.
14629  Action varies depending on whether it is a completely new route, or an extension of an existing route at the
14630  beginning or the end.
14631  Ignore if SearchVector empty, and check that all the new elements in SearchVector are valid.
14632  Check if route end selection is in an existing route (ReqPosRouteID > -1), if so and existing route is non-autosigs
14633  add its elements to the SearchVector then delete the route, decrementing StartSelectionRouteNumber if the RequPosRouteNumber was
14634  less than StartSelectionRouteID. If existing route is AutoSigs then the final search element is dropped from the SearchVector,
14635  since the new route will end adjacent to the AutoSigs route, and the existing route is left as it is.
14636  Note that a single route cannot contain both AutoSig & non-AutoSig elements, each route of AutoSig elements
14637  has its own identity. A single route can however have a mixture of Unrestricted and PreferredRoute elements
14638 
14639  Check if StartSelectionRouteID set (extending an existing route) and if so and if existing route non-autosig, then add the new route
14640  to the existing route (start element not stored in searchvector), call SetRoutePoints & SetRouteSignals for the extended route and return.
14641  If the existing route is autosig, then leave the existing route as it is and continue as for routes that aren't linked to an existing
14642  route at the start.
14643 
14644  Check the validity of the route in SearchVector, and create a new route using StoreOneRoute. Finally call SetRoutePoints & SetRouteSignals
14645  for the new route and return.
14646 */
14647 
14648 {
14649  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConvertAndAddNonPreferredRouteSearchVector," +
14650  AnsiString(ReqPosRouteID.GetInt()));
14651  if(SearchVector.size() < 1)
14652  {
14653  Utilities->CallLogPop(306);
14654  return;
14655  }
14656  PrefDirVector = SearchVector; // this copy is to validate the vector up to this point,
14657  if(!ValidatePrefDir(6))
14658  {
14659  Utilities->CallLogPop(307);
14660  return;
14661  }
14662 
14663  TAllRoutes::TLockedRouteClass LockedRouteObject;
14664 
14666  unsigned int TruncatePrefDirPosition = 0;
14667 
14668  if(ReqPosRouteID > -1) // Note that ReqPosRouteID != StartSelectionRouteID as would have failed in GetNextRouteElement
14669 /* if have ReqPosRouteID:
14670  if existing route non-autosig, then add the old route to the SearchVector then delete the old route
14671  if existing route autosig, drop the final search element in the new route, leave the existing route as it is,
14672  then enter the new route into the AllRoutesVector
14673 */
14674  {
14676  {
14677  for(unsigned int x = 1; x < AllRoutes->GetFixedRouteAtIDNumber(46, ReqPosRouteID).PrefDirSize();
14678  x++) // start at 1 as first element already in SearchVector
14679  {
14681  }
14682  // note that route numbers in map adjusted when ReqPos route cleared
14684  // create a new locked route object (apart from RouteNumber) if required, for use later (LockedRouteFoundDuringRouteBuilding
14685  // set during ClearRouteDuringRouteBuildingAt)
14687  {
14690  LockedRouteObject.LastXLinkPos = AllRoutes->LockedRouteLastXLinkPos;
14691  LockedRouteObject.LockStartTime = AllRoutes->LockedRouteLockStartTime;
14692  }
14693  }
14695  {
14696  SearchVector.pop_back();
14697  }
14698  }
14699 
14700  if(StartSelectionRouteID > -1)
14701 /* if have StartSelectionRouteID:
14702  if existing route non-autosig, then add the new route to the existing route (start element not stored in searchvector)
14703  if existing route autosig, leave the existing route as it is, and just enter the new route into the AllRoutesVector
14704 */
14705  {
14707  // need to test because may have been removed by a train moving in the wrong direction between first and last route selections - added at v1.3.1
14708  {
14710  {
14711  int RouteNumber = AllRoutes->GetRouteVectorNumber(1, StartSelectionRouteID);
14712  for(unsigned int x = 0; x < SearchVector.size(); x++)
14713  {
14715  RouteNumber, GetFixedSearchElementAt(7, x));
14716  // find & store locked route truncate position in PrefDirVector for later use
14718  {
14719  if(GetFixedSearchElementAt(16, x).TrackVectorPosition == int(AllRoutes->LockedRouteTruncateTrackVectorPosition))
14720  {
14721  TruncatePrefDirPosition = AllRoutes->GetFixedRouteAt(176, RouteNumber).PrefDirSize() - 1;
14722  }
14723  }
14724  }
14726  {
14727  throw Exception("Failed to validate extended route for nonpreferred route");
14728  }
14731  AllRoutes->GetModifiableRouteAtIDNumber(9, StartSelectionRouteID).SetLCChangeValues(2, false); // ConsecSignalsRoute is false
14732  // now add the reinstated locked route if required and set signals accordingly
14733  // shouldn't ever need to access this as the train that has caused the locked route will be ahead of the route to be added,
14734  // and it will have removed the route elements that it is standing on, but include in case there's some obscure condition
14735  // that I haven't thought of
14737  {
14738  LockedRouteObject.RouteNumber = RouteNumber;
14739  AllRoutes->LockedRouteVector.push_back(LockedRouteObject);
14740  // now reset the signals for the locked route
14741  AllRoutes->SetAllRearwardsSignals(12, 0, RouteNumber, TruncatePrefDirPosition);
14742  for(int c = AllRoutes->GetFixedRouteAt(177, RouteNumber).PrefDirSize() - 1; c >= (int)TruncatePrefDirPosition;
14743  c--) // must use int for >= test to succeed when TruncatePrefDirPosition == 0
14744  // return all signals to red in route section to be truncated
14745  {
14746  TPrefDirElement PrefDirElement = AllRoutes->GetFixedRouteAt(178, RouteNumber).PrefDirVector.at(c);
14747  TTrackElement & TrackElement = Track->TrackElementAt(813, PrefDirElement.TrackVectorPosition);
14748  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal)
14749  {
14750  TrackElement.Attribute = 0;
14751  Track->PlotSignal(11, TrackElement, Display);
14752  Display->PlotOutput(115, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EXGraphicPtr);
14753  Display->PlotOutput(116, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EntryDirectionGraphicPtr);
14754  }
14755  }
14756  }
14757  AllRoutes->CheckMapAndRoutes(3); // test
14758  Utilities->CallLogPop(308);
14759  return;
14760  }
14761  }
14762  else
14763  {
14765  }
14766 // if new route non-autosig and existing route autosig, leave the existing route as it is, and just enter the new route into the AllRoutesVector
14767 // hence nothing to do here
14768  }
14769 
14770  PrefDirVector = SearchVector; // copy again prior to storing as a route as SearchVector may have been extended
14771  if(!ValidatePrefDir(8)) // validate PrefDir for all new route elements
14772  {
14773  throw Exception("Failed to validate single route for nonpreferred route");
14774  }
14775  AllRoutes->StoreOneRoute(2, this);
14776  AllRoutes->GetModifiableRouteAt(6, AllRoutes->AllRoutesSize() - 1).SetRoutePoints(3); // new addition
14777  AllRoutes->GetModifiableRouteAt(17, AllRoutes->AllRoutesSize() - 1).SetRouteSignals(7); // new addition
14778  AllRoutes->GetModifiableRouteAt(19, AllRoutes->AllRoutesSize() - 1).SetLCChangeValues(3, false); // ConsecSignalsRoute is false
14779  AllRoutes->CheckMapAndRoutes(4); // test
14780  Utilities->CallLogPop(309);
14781 }
14782 
14783 // ---------------------------------------------------------------------------
14784 
14785 void TOneRoute::SetRoutePoints(int Caller) const
14786 /*
14787  Examine each set of points in the route to see if entry or exit is via the straight or diverging trailing
14788  link, and set the attribute accordingly (don't need to worry about linked routes, points in those will have been set
14789  when they were created.
14790 */
14791 {
14792  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRoutePoints");
14793  if(!PrefDirVector.empty())
14794  {
14795  for(TPrefDirVectorConstIterator PrefDirPtr = (PrefDirVector.end() - 1); PrefDirPtr >= PrefDirVector.begin(); PrefDirPtr--)
14796  {
14797  if((PrefDirPtr->TrackType == Points) && ((PrefDirPtr->ELinkPos == 1) || (PrefDirPtr->XLinkPos == 1))) // 1=straight trailing
14798  {
14799  Track->TrackElementAt(96, PrefDirPtr->TrackVectorPosition).Attribute = 0; // 0=straight
14800  Track->PlotPoints(3, Track->TrackElementAt(97, PrefDirPtr->TrackVectorPosition), Display, false);
14801  }
14802  if((PrefDirPtr->TrackType == Points) && ((PrefDirPtr->ELinkPos == 3) || (PrefDirPtr->XLinkPos == 3))) // 3=diverging trailing
14803  {
14804  Track->TrackElementAt(98, PrefDirPtr->TrackVectorPosition).Attribute = 1; // 1=diverging
14805  Track->PlotPoints(4, Track->TrackElementAt(99, PrefDirPtr->TrackVectorPosition), Display, false);
14806  }
14807  }
14808  }
14809  Utilities->CallLogPop(327);
14810 }
14811 
14812 // ---------------------------------------------------------------------------
14813 
14814 void TOneRoute::SetRouteSignals(int Caller) const
14815 /* Used for new train additions in AddTrain and in route setting
14816  Set the signals as follows:-
14817  First check whether there is a linked forward route, and if so use FindForwardTargetSignalAttribute to work along it from the start
14818  until find a train (return Attribute = 0 & NextForwardLinkedRouteNumber = -1), a buffer (return Attribute = 1 &
14819  NextForwardLinkedRouteNumber = -1), a continuation (return Attribute = 3 & NextForwardLinkedRouteNumber = -1) or a forward-facing
14820  signal. If find a signal its attribute value + 1 up to a maximum value of 3 is returned & NextForwardLinkedRouteNumber = -1.
14821  The above Attribute values represent the 'target' attribute, from which all rearwards signals in turn in the new route are set,
14822  the first using the returned attribute value and subsequent ones incrementing the Attribute up to a maximum of 3. All the foregoing
14823  return true, as does finding none of the above and no onward linked forward route (NextForwardLinkedRouteNumber = -1). If none
14824  of the foregoing are found but there is a further forward linked forward route then the function returns false with
14825  NextForwardLinkedRouteNumber = the next forward linked route number, to allow that to be examined similarly, and Attribute = 0.
14826 
14827  When the target Attribute is found (will be 0 if no forward linked route), then SetAllRearwardsSignals is used to work back from
14828  the end of the route setting each forward-facing signal one step nearer green as described above, until either reach the end of all
14829  linked rearwards routes or find a train. If find a train in the current route then signals behind it (and behind any other trains
14830  in the current route) are set appropriately (including in linked rear routes), but if find a train in a linked rear route then no
14831  further signals are set. If there is no forward linked route and the front end of the current route is a buffer then
14832  SetAllRearwardsSignals (in its call to SetRearwardsSignalsReturnFalseForTrain) treats it as a red signal, and if a continuation,
14833  as a green signal.
14834 */
14835 {
14836  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRouteSignals");
14837  if(!PrefDirVector.empty())
14838  {
14839  // get target Attribute value, check first if there is a forward linked route
14840  TPrefDirElement LastElement = GetFixedPrefDirElementAt(185, PrefDirSize() - 1);
14841  TPrefDirElement FirstElement = GetFixedPrefDirElementAt(186, 0);
14842  int ForwardLinkedRouteNumber, Attribute = 0;
14843  if(LastElement.Conn[LastElement.XLinkPos] > -1)
14844  // Note that LastElement can't be points but can be linked to points
14845  {
14846  if(AllRoutes->GetRouteTypeAndNumber(16, LastElement.Conn[LastElement.XLinkPos], LastElement.ConnLinkPos[LastElement.XLinkPos],
14847  ForwardLinkedRouteNumber) != TAllRoutes::NoRoute)
14848  {
14849  if(ForwardLinkedRouteNumber > -1)
14850  {
14851  int NextForwardLinkedRouteNumber = -1;
14852  while(!(AllRoutes->GetFixedRouteAt(171, ForwardLinkedRouteNumber).FindForwardTargetSignalAttribute(1, NextForwardLinkedRouteNumber,
14853  Attribute)))
14854  {
14855  ForwardLinkedRouteNumber = NextForwardLinkedRouteNumber;
14856  }
14857  // if find a train before a signal then Attribute = 0, else if find end of route is a buffer then Attribute = 1, or a continuation then
14858  // Attribute = 3, else if find signal then Attribute = (signal attribute + 1) up to a max value of 3. All these return true, if find a
14859  // forward linked route then the routenumber is set in NextForwardLinkedRouteNumber, Attribute = 0 & returns false.
14860  }
14861  }
14862  }
14863  int RouteNumber;
14864  TAllRoutes::TRouteType RouteType = AllRoutes->GetRouteTypeAndNumber(15, GetFixedPrefDirElementAt(187, 0).TrackVectorPosition,
14865  GetFixedPrefDirElementAt(193, 0).XLinkPos, RouteNumber);
14866  if(RouteType != TAllRoutes::NoRoute)
14867  // it will be, above only used to get RouteNumber, can choose any element in the route so use GetFixedPrefDirElementAt
14868  {
14869  AllRoutes->SetAllRearwardsSignals(8, Attribute, RouteNumber, PrefDirSize() - 1);
14870  }
14871  }
14872  Utilities->CallLogPop(1720);
14873 }
14874 
14875 // ---------------------------------------------------------------------------
14876 
14877 bool TOneRoute::PointsToBeChanged(int Caller) const
14878 { // true if at any point in SearchVector points have to be changed
14879  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PointsToBeChanged");
14880  if(!SearchVector.empty())
14881  {
14882  for(TPrefDirVectorConstIterator SearchPtr = SearchVector.begin(); SearchPtr != SearchVector.end(); SearchPtr++)
14883  {
14884  if((SearchPtr->TrackType == Points) && ((SearchPtr->ELinkPos == 1) || (SearchPtr->XLinkPos == 1))) // 1=straight trailing
14885  {
14886  if(Track->TrackElementAt(752, SearchPtr->TrackVectorPosition).Attribute != 0) // 0=straight or LH
14887  {
14888  Utilities->CallLogPop(1717);
14889  return true;
14890  }
14891  }
14892  if((SearchPtr->TrackType == Points) && ((SearchPtr->ELinkPos == 3) || (SearchPtr->XLinkPos == 3))) // 3=diverging trailing
14893  {
14894  if(Track->TrackElementAt(753, SearchPtr->TrackVectorPosition).Attribute != 1) // 1=diverging or RH
14895  {
14896  Utilities->CallLogPop(1718);
14897  return true;
14898  }
14899  }
14900  }
14901  }
14902  Utilities->CallLogPop(1719);
14903  return false;
14904 }
14905 
14906 // ---------------------------------------------------------------------------
14907 
14908 bool TOneRoute::FindForwardTargetSignalAttribute(int Caller, int &NextForwardLinkedRouteNumber, int &Attribute) const
14909 /*
14910  Works forward through the route until finds:-
14911  (a) a train - Attribute = 0, NextForwardLinkedRouteNumber = -1 & returns true;
14912  (b) end of route at buffers - Attribute = 1, NextForwardLinkedRouteNumber = -1 & returns true;
14913  (c) end of route at continuation - Attribute = 3, NextForwardLinkedRouteNumber = -1 & returns true;
14914  (d) level crossing with barriers not down - Attribute = 0, NextForwardLinkedRouteNumber = -1 & returns true;
14915  (e) forward-facing signal - Attribute = 1 + signal attribute (max value of 3), NextForwardLinkedRouteNumber = -1 & returns true;
14916  (f) end of route not at any of foregoing and with no linked forward route - Attribute = 0, NextForwardLinkedRouteNumber = -1 &
14917  returns true;
14918  (g) linked forward route - Attribute = 0, NextForwardLinkedRouteNumber = the routenumber of the forward route & returns false.
14919 */
14920 {
14921  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindForwardTargetSignalAttribute");
14922  Attribute = 0;
14923  NextForwardLinkedRouteNumber = -1;
14924  for(unsigned int x = 0; x < PrefDirSize(); x++)
14925  {
14926  int TrainID = Track->TrackElementAt(100, PrefDirVector.at(x).TrackVectorPosition).TrainIDOnElement;
14927  if(PrefDirVector.at(x).TrackType == Bridge)
14928  {
14929  if(PrefDirVector.at(x).XLinkPos < 2)
14930  TrainID = Track->TrackElementAt(101, PrefDirVector.at(x).TrackVectorPosition).TrainIDOnBridgeTrackPos01;
14931  else
14932  TrainID = Track->TrackElementAt(102, PrefDirVector.at(x).TrackVectorPosition).TrainIDOnBridgeTrackPos23;
14933  }
14934  if(TrainID != -1)
14935  {
14936  Utilities->CallLogPop(328);
14937  return true;
14938  }
14939  if(PrefDirVector.at(x).TrackType == Buffers)
14940  {
14941  Attribute = 1;
14942  Utilities->CallLogPop(329);
14943  return true;
14944  }
14945  if(PrefDirVector.at(x).TrackType == Continuation)
14946  {
14947  Attribute = 3;
14948  Utilities->CallLogPop(330);
14949  return true;
14950  }
14951  if(Track->IsLCAtHV(42, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc))
14952  {
14953  if(!Track->IsLCBarrierDownAtHV(3, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc))
14954  {
14955  Attribute = 0;
14956  Utilities->CallLogPop(1950);
14957  return true;
14958  }
14959  }
14960  if(PrefDirVector.at(x).Config[PrefDirVector.at(x).XLinkPos] == Signal)
14961  {
14962  Attribute = Track->TrackElementAt(103, PrefDirVector.at(x).TrackVectorPosition).Attribute + 1;
14963  if(Attribute > 3)
14964  Attribute = 3;
14965  Utilities->CallLogPop(331);
14966  return true;
14967  }
14968  if(x == PrefDirSize() - 1)
14969  {
14970  TPrefDirElement LastElement = PrefDirVector.at(x);
14971  if(LastElement.Conn[LastElement.XLinkPos] > -1)
14972  {
14973  if(AllRoutes->GetRouteTypeAndNumber(2, LastElement.Conn[LastElement.XLinkPos],
14974  Track->GetNonPointsOppositeLinkPos(LastElement.ConnLinkPos[LastElement.XLinkPos]), NextForwardLinkedRouteNumber) != TAllRoutes::NoRoute)
14975  {
14976  Attribute = 0;
14977  Utilities->CallLogPop(332);
14978  return false;
14979  }
14980  }
14981  }
14982  }
14983  Utilities->CallLogPop(333);
14984  return true;
14985 }
14986 
14987 // ---------------------------------------------------------------------------
14988 
14989 bool TOneRoute::SetRearwardsSignalsReturnFalseForTrain(int Caller, int &Attribute, int PrefDirVectorStartPosition) const
14990 /*
14991  This function is only called by TAllRoutes::SetAllRearwardsSignals.
14992 
14993  Enter with Attribute set to the value to be used (unless modified by the initial forward search - see later) for the first rearwards
14994  signal found, and with PrefDirVectorStartPosition set to the position in PrefDirVector to begin the search. BUT, don't begin with the
14995  rearward search, first search forwards from the PrefDirVectorStartPosition in case the end of the route is a buffer or continuation, and
14996  modify the Attribute accordingly UNLESS (a) train present between PrefDirVectorStartPosition & end; (b) route in
14997  ContinuationAutoSigVector (i.e. train has exited the route at a continuation but it is still affecting the signals), or (c) truncating
14998  a route.
14999 
15000  Having received or modified Attribute as above, work backwards from the PrefDirVectorStartPosition until find a train - return false, or a
15001  signal. If find a signal (but see note below) set its Attribute to the current Attribute value up to a maximum of 3, and replot the signal as well as
15002  the required route and direction (if required) graphics, then increment Attribute up to a max. of 3. On completion Attribute is
15003  passed back from the function as a reference. If no train is found before the beginning of the route is reached the function returns true.
15004 
15005  In setting signals skip the first position if it's a signal and if truncating - otherwise the truncated signal counts as the first red
15006  and the next rearwards signal becomes yellow, although it's the first in the route
15007 */
15008 {
15009  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRearwardsSignalsReturnFalseForTrain," + AnsiString(Attribute) + "," +
15010  AnsiString(PrefDirVectorStartPosition));
15011  Graphics::TBitmap *EXGraphicPtr = RailGraphics->bmTransparentBgnd; // default values
15012  Graphics::TBitmap *EntryDirectionGraphicPtr = RailGraphics->bmTransparentBgnd;
15013 // if no train between end of route and PrefDirVectorStartPosition, route not in ContinuationAutoSigVector
15014 // & not truncating a route, then Attribute can be modified if end is buffers or continuation
15015  bool SkipContinuationAndBufferAttributeChange = false;
15016 
15017  if(!PrefDirVector.empty())
15018  {
15019  for(TPrefDirVectorConstIterator PrefDirPtr = (PrefDirVector.begin() + PrefDirVectorStartPosition); PrefDirPtr < PrefDirVector.end(); PrefDirPtr++)
15020  {
15021  int TrainID = Track->TrackElementAt(104, PrefDirPtr->TrackVectorPosition).TrainIDOnElement;
15022  if(PrefDirPtr->TrackType == Bridge)
15023  {
15024  if(PrefDirPtr->XLinkPos < 2)
15025  TrainID = Track->TrackElementAt(105, PrefDirPtr->TrackVectorPosition).TrainIDOnBridgeTrackPos01;
15026  else
15027  TrainID = Track->TrackElementAt(106, PrefDirPtr->TrackVectorPosition).TrainIDOnBridgeTrackPos23;
15028  }
15029  if(TrainID != -1)
15030  {
15031  SkipContinuationAndBufferAttributeChange = true;
15032  break;
15033  }
15034  }
15035 
15038  {
15039  for(AutoSigVectorIT = TrainController->ContinuationAutoSigVector.begin(); AutoSigVectorIT < TrainController->ContinuationAutoSigVector.end();
15040  AutoSigVectorIT++)
15041  {
15042  if(!AllRoutes->AllRoutesVector.empty())
15043  {
15044  if((&AllRoutes->AllRoutesVector.front() + AutoSigVectorIT->RouteNumber) == this)
15045  {
15046  SkipContinuationAndBufferAttributeChange = true;
15047  break;
15048  }
15049  }
15050  }
15051  }
15052 
15054  SkipContinuationAndBufferAttributeChange = true;
15055 
15056  if(!SkipContinuationAndBufferAttributeChange)
15057  {
15058  if(PrefDirVector.back().TrackType == Buffers)
15059  Attribute = 1; // treat buffer as red signal
15060  if(PrefDirVector.back().TrackType == Continuation)
15061  Attribute = 3; // treat continuation as a green signal
15062  }
15063 
15064  for(TPrefDirVectorConstIterator PrefDirPtr = (PrefDirVector.begin() + PrefDirVectorStartPosition); PrefDirPtr >= PrefDirVector.begin(); PrefDirPtr--)
15065  {
15066  int TrainID = Track->TrackElementAt(107, PrefDirPtr->TrackVectorPosition).TrainIDOnElement;
15067  if(PrefDirPtr->TrackType == Bridge)
15068  {
15069  if(PrefDirPtr->XLinkPos < 2)
15070  TrainID = Track->TrackElementAt(108, PrefDirPtr->TrackVectorPosition).TrainIDOnBridgeTrackPos01;
15071  else
15072  TrainID = Track->TrackElementAt(109, PrefDirPtr->TrackVectorPosition).TrainIDOnBridgeTrackPos23;
15073  }
15074  if(TrainID != -1)
15075  {
15076  Utilities->CallLogPop(334);
15077  return false;
15078  }
15079  // if find an LC that is closed to trains (or flashing - may be extending an earlier route with flashing LCs) then reset
15080  // the attribute to 0 so first signal behind the LC is red
15081  if(Track->IsLCAtHV(20, PrefDirPtr->HLoc, PrefDirPtr->VLoc))
15082  {
15083  if(!Track->IsLCBarrierDownAtHV(1, PrefDirPtr->HLoc, PrefDirPtr->VLoc))
15084  {
15085  Attribute = 0;
15086  }
15087  }
15088 // now set signals, but skip the first position if it's a signal on an unrestricted route and truncating - otherwise the truncated signal
15089 // counts as the first red and the next rearwards signal becomes yellow, although it's the first in the route
15090  if(PrefDirPtr->Config[PrefDirPtr->XLinkPos] == Signal)
15091  {
15092  if((!AllRoutes->RouteTruncateFlag) || (PrefDirPtr != (PrefDirVector.begin() + PrefDirVectorStartPosition)) || PrefDirPtr->AutoSignals ||
15093  PrefDirPtr->ConsecSignals)
15094  {
15095  if(Attribute < 3)
15096  Track->TrackElementAt(110, PrefDirPtr->TrackVectorPosition).Attribute = Attribute;
15097  else
15098  Track->TrackElementAt(111, PrefDirPtr->TrackVectorPosition).Attribute = 3; // green
15099  Track->PlotSignal(1, Track->TrackElementAt(112, PrefDirPtr->TrackVectorPosition), Display);
15100  if(AllRoutes->GetRouteTypeAndGraphics(1, PrefDirPtr->TrackVectorPosition, PrefDirPtr->XLinkPos, EXGraphicPtr,
15101  EntryDirectionGraphicPtr) != TAllRoutes::NoRoute)
15102  {
15103  Display->PlotOutput(16, Track->TrackElementAt(113, PrefDirPtr->TrackVectorPosition).HLoc * 16,
15104  Track->TrackElementAt(114, PrefDirPtr->TrackVectorPosition).VLoc * 16, EXGraphicPtr);
15105  Display->PlotOutput(17, Track->TrackElementAt(115, PrefDirPtr->TrackVectorPosition).HLoc * 16,
15106  Track->TrackElementAt(116, PrefDirPtr->TrackVectorPosition).VLoc * 16, EntryDirectionGraphicPtr);
15107  }
15108  if(Attribute < 3)
15109  Attribute++;
15110  Display->Update(); // update after recent plots
15111  }
15112  }
15113  }
15114  }
15115  Utilities->CallLogPop(335);
15116  return true;
15117 }
15118 
15119 // ---------------------------------------------------------------------------
15120 
15121 void TOneRoute::GetRouteTruncateElement(int Caller, int HLoc, int VLoc, bool ConsecSignalsRoute, TTruncateReturnType &ReturnFlag)
15122 /*
15123  Examines the route to see whether the element at H & V is in the route, and if not returns a ReturnFlag value of NotInRoute.
15124  If it is in a route but the element selected is invalid, then a message is given and returns with a ReturnFlag value of
15125  InRouteFalse. Otherwise the route is truncated at and including the element that matches H & V with a ReturnFlag value of InRouteTrue.
15126  Selection invalid if a train at or before the truncate point; select a bridge; trying to leave a single element; last element to be left
15127  not a signal (for ConsecSignalsRoute or has AutoSigsFlag set); last element to be left a bridge, points or crossover (for not
15128  ConsecSignalsRoute & AutoSigsFlag not set), or part of route locked. Check if a train approaching or occupying route and lock route
15129  if required after offering the user the choice to continue or not. Then SetAllRearwardsSignals is called to set signals before the
15130  truncate point, beginning with a red signal, and RemoveRouteElement called for all elements from the end to and including the truncate point.
15131 */
15132 {
15133  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteTruncateElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
15134  "," + AnsiString((short)ConsecSignalsRoute));
15135  bool ElementInRoute = false;
15136  bool TrainOccupyingRoute = false;
15137 
15138  for(unsigned int b = 0; b < PrefDirSize(); b++)
15139  {
15140  if((PrefDirVector.at(b).HLoc == HLoc) && (PrefDirVector.at(b).VLoc == VLoc))
15141  {
15142  ElementInRoute = true;
15143  break;
15144  }
15145  }
15146  if(!ElementInRoute)
15147  {
15148  ReturnFlag = NotInRoute;
15149  Utilities->CallLogPop(336);
15150  return;
15151  }
15152 // it is in the route so continue, first look for a train or a flashing level crossing
15153  for(int b = PrefDirSize() - 1; b >= 0; b--)
15154  {
15155  int TrainID = Track->TrackElementAt(117, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnElement;
15156  if(PrefDirVector.at(b).TrackType == Bridge)
15157  {
15158  if(PrefDirVector.at(b).XLinkPos < 2)
15159  TrainID = Track->TrackElementAt(118, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnBridgeTrackPos01;
15160  else
15161  TrainID = Track->TrackElementAt(119, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnBridgeTrackPos23;
15162  }
15163  if(TrainID != -1)
15164  {
15165 // TrainController->StopTTClockMessage(56, "Can't truncate a route that is occupied by a train");
15166 // ReturnFlag = InRouteFalse;
15167 // Utilities->CallLogPop(337);
15168 // return;
15169 // above removed at v2.1.0 so that routes can be locked when occupied, below added
15170  TrainOccupyingRoute = true; // train is forward of the truncate point
15171  }
15172  if(Track->IsLCBarrierFlashingAtHV(3, PrefDirVector.at(b).HLoc, PrefDirVector.at(b).VLoc))
15173  {
15174  TrainController->StopTTClockMessage(79, "Can't cancel a route containing a level crossing that is changing state");
15175  ReturnFlag = InRouteFalse;
15176  Utilities->CallLogPop(1941);
15177  return;
15178  }
15179  if((PrefDirVector.at(b).HLoc == HLoc) && (PrefDirVector.at(b).VLoc == VLoc))
15180  {
15181  break; // OK found truncate element & no flashing LC in front
15182  }
15183  }
15184 
15185  for(unsigned int b = 0; b < PrefDirSize(); b++)
15186  {
15187  if((PrefDirVector.at(b).HLoc == HLoc) && (PrefDirVector.at(b).VLoc == VLoc)) // b = the truncate point
15188  {
15189  if(PrefDirVector.at(b).TrackType == Bridge)
15190  {
15191  TrainController->StopTTClockMessage(57, "Can't select a bridge as a route truncate point");
15192  ReturnFlag = InRouteFalse;
15193  Utilities->CallLogPop(338);
15194  return;
15195  }
15196  if(b == 1)
15197  {
15198  TrainController->StopTTClockMessage(58, "Can't truncate to a single route element");
15199  ReturnFlag = InRouteFalse;
15200  Utilities->CallLogPop(339);
15201  return;
15202  }
15203  if(b > 0)
15204  {
15205  TPrefDirElement TempElement = PrefDirVector.at(b - 1);
15206  if(TempElement.ConsecSignals || TempElement.AutoSignals)
15207  {
15208  if(TempElement.Config[TempElement.XLinkPos] != Signal)
15209  {
15210  TrainController->StopTTClockMessage(59, "Must truncate to a valid signal - select position after signal");
15211  ReturnFlag = InRouteFalse;
15212  Utilities->CallLogPop(340);
15213  return;
15214  }
15215  }
15216  else
15217  {
15218  if((TempElement.TrackType == Points) || (TempElement.TrackType == Crossover) || (TempElement.TrackType == Bridge))
15219  {
15220  TrainController->StopTTClockMessage(60, "Can't truncate to points, bridge or crossover");
15221  ReturnFlag = InRouteFalse;
15222  Utilities->CallLogPop(341);
15223  return;
15224  }
15225  }
15226  }
15227 
15228  int RouteNumber;
15230 // Have to call RouteLockingRequired before SetAllRearwardsSignals because RouteLockingRequired tests the first rearward signal, if it is
15231 // red then locking is not required, and if call SetAllRearwardsSignals first then it will set the first rearward signal to red.
15232 
15233 // check if part of this route already locked & disallow if so
15234  if(!(AllRoutes->LockedRouteVector.empty()))
15235  {
15237  {
15238  if(LRVIT->RouteNumber == RouteNumber)
15239  {
15240  TrainController->StopTTClockMessage(61, "Can't truncate a route that is already part-locked");
15241  ReturnFlag = InRouteFalse;
15242  Utilities->CallLogPop(749);
15243  return;
15244  }
15245  }
15246  }
15247 
15248  if(AllRoutes->RouteLockingRequired(0, RouteNumber, b) || TrainOccupyingRoute) // added TrainOccupyingRoute at v2.1.0,
15249  // RouteLockingRequired only checks for trains approaching
15250  {
15253  int button = Application->MessageBox(L"Train approaching or occupying route, YES to lock route (2 minutes to release), NO to cancel",
15254  L"Warning!", MB_YESNO | MB_ICONWARNING);
15255  TrainController->BaseTime = TDateTime::CurrentDateTime();
15257  if(button == IDNO)
15258  {
15259  ReturnFlag = InRouteTrue; // still return true even though don't act on it
15260  Utilities->CallLogPop(342);
15261  return;
15262  }
15263  AnsiString LocID = AnsiString(Track->TrackElementAt(534, PrefDirVector.at(b).TrackVectorPosition).ElementID);
15264  TrainController->LogActionError(0, "", "", FailLockedRoute, LocID);
15265  TAllRoutes::TLockedRouteClass LockedRoute;
15266  bool ExistingLockedRouteModified = false;
15267  LockedRoute.RouteNumber = RouteNumber;
15268  LockedRoute.TruncateTrackVectorPosition = PrefDirVector.at(b).TrackVectorPosition;
15269  LockedRoute.LastTrackVectorPosition = PrefDirVector.at(PrefDirSize() - 1).TrackVectorPosition;
15270  LockedRoute.LastXLinkPos = PrefDirVector.at(PrefDirSize() - 1).XLinkPos;
15271  LockedRoute.LockStartTime = TrainController->TTClockTime;
15272 // but first check if this route already in LockedRouteVector (i.e. locked further along), and if so just change that vector entry
15273 // to use the new TruncateTrackVectorPosition & LockStartTime
15274  if(!AllRoutes->LockedRouteVector.empty())
15275  {
15276  for(TAllRoutes::TLockedRouteVectorIterator LRVIT = AllRoutes->LockedRouteVector.begin(); LRVIT < AllRoutes->LockedRouteVector.end();
15277  LRVIT++)
15278  {
15279  if(LRVIT->RouteNumber == RouteNumber)
15280  {
15281  LRVIT->TruncateTrackVectorPosition = LockedRoute.TruncateTrackVectorPosition;
15282  LRVIT->LockStartTime = LockedRoute.LockStartTime;
15283  ExistingLockedRouteModified = true;
15284  }
15285  }
15286  }
15287  if(!ExistingLockedRouteModified)
15288  AllRoutes->LockedRouteVector.push_back(LockedRoute);
15289  AllRoutes->SetAllRearwardsSignals(2, 0, RouteNumber, b);
15290  for(int c = PrefDirSize() - 1; c >= (int)b; c--) // must use int for >= test to succeed when b == 0
15291  // return all signals to red in route section to be truncated
15292  {
15293  TPrefDirElement PrefDirElement = AllRoutes->GetFixedRouteAt(61, RouteNumber).PrefDirVector.at(c);
15294  TTrackElement & TrackElement = Track->TrackElementAt(120, PrefDirElement.TrackVectorPosition);
15295  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal)
15296  {
15297  TrackElement.Attribute = 0;
15298  Track->PlotSignal(2, TrackElement, Display);
15299  Display->PlotOutput(18, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EXGraphicPtr);
15300  Display->PlotOutput(19, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EntryDirectionGraphicPtr);
15301  }
15302  }
15303 // Display->Update();//not needed as Clearand... called on return from GetAllRoutesTruncateElement in InterfaceUnit
15304  ReturnFlag = InRouteTrue;
15305  }
15306  else
15307  {
15308  AllRoutes->SetAllRearwardsSignals(3, 0, RouteNumber, b);
15309  for(int c = PrefDirSize() - 1; c >= (int)b; c--) // must use int for >= test to succeed when b == 0
15310  {
15311  AllRoutes->RemoveRouteElement(5, LastElementPtr(3)->HLoc, LastElementPtr(4)->VLoc, LastElementPtr(5)->ELink);
15312  ReturnFlag = InRouteTrue;
15313  }
15314  }
15315  AllRoutes->CheckMapAndRoutes(5); // test
15316  Utilities->CallLogPop(343);
15317  return;
15318  }
15319  }
15320  ReturnFlag = NotInRoute;
15321  Utilities->CallLogPop(344);
15322 }
15323 
15324 // ---------------------------------------------------------------------------
15326 /*
15327  This is used when a train enters a route set in the opposite direction of travel (or at a crossover on a non-route line when the other
15328  track is in a route). The complete route is cancelled (but not linked routes), and all signals in the route are set to red.
15329  First all signals are set to red and replotted (without any route colours), then SetAllRearwardsSignals is called from the
15330  beginning of the route to set all linked rearwards route signals appropriately. Then all elements are removed from the route
15331  and RebuildRailwayFlag set (examined in Interface unit at each clock tick) to force a ClearandRebuildRailway to get rid of
15332  the route colours.
15333 */
15334 {
15335  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ForceCancelRoute");
15336  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
15338  int RouteNumber;
15339  TAllRoutes::TRouteType RouteType = AllRoutes->GetRouteTypeAndNumber(4, GetFixedPrefDirElementAt(86, 0).TrackVectorPosition,
15340  GetFixedPrefDirElementAt(87, 0).XLinkPos, RouteNumber);
15341 
15342  if(RouteType != TAllRoutes::NoRoute) // it won't be, above only used to get RouteNumber for setting rearwards signals
15343  {
15344  for(unsigned int x = 0; x < PrefDirSize(); x++) // set all signals in route to red regardless of direction
15345  {
15346  if(PrefDirVector.at(x).TrackType == SignalPost)
15347  {
15348  Track->TrackElementAt(121, PrefDirVector.at(x).TrackVectorPosition).Attribute = 0; // red
15349  Track->PlotSignal(3, Track->TrackElementAt(122, PrefDirVector.at(x).TrackVectorPosition), Display);
15350  }
15351  }
15352  AllRoutes->SetAllRearwardsSignals(4, 0, RouteNumber, 0);
15353 // already set all signals to red in route so start at start of route for further rearwards signal setting
15354  }
15355  for(int c = PrefDirSize() - 1; c >= 0; c--) // must use int for >= test to succeed when b == 0
15356  {
15357  AllRoutes->RemoveRouteElement(6, LastElementPtr(6)->HLoc, LastElementPtr(7)->VLoc, LastElementPtr(8)->ELink);
15358  }
15359  AllRoutes->RebuildRailwayFlag = true; // set to force a ClearandRebuildRailway at next clock tick if not in zoom-out mode
15360  AllRoutes->CheckMapAndRoutes(9); // test
15361  TrainController->BaseTime = TDateTime::CurrentDateTime();
15363  Utilities->CallLogPop(345);
15364  return;
15365 }
15366 
15367 // ---------------------------------------------------------------------------
15368 
15369 void TOneRoute::SetRouteSearchVectorGraphics(int Caller, bool AutoSigsFlag, bool ConsecSignalsRoute)
15370 /*
15371  Set values for EXGraphicPtr and EntryDirectionGraphicPtr for all elements in SearchVector.
15372 */
15373 {
15374  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRouteSearchVectorGraphics," + AnsiString((short)AutoSigsFlag) + "," +
15375  AnsiString((short)ConsecSignalsRoute));
15376  if(SearchVector.empty())
15377  {
15378  Utilities->CallLogPop(1149);
15379  return;
15380  }
15381  for(unsigned int b = 0; b < SearchVector.size(); b++)
15382  {
15383  GetModifiableSearchElementAt(1, b).EXGraphicPtr = GetModifiableSearchElementAt(2, b).GetRouteGraphicPtr(AutoSigsFlag, ConsecSignalsRoute);
15385  ConsecSignalsRoute);
15386  }
15387  Utilities->CallLogPop(346);
15388 }
15389 
15390 // ---------------------------------------------------------------------------
15391 
15392 void TOneRoute::SetRouteFlashValues(int Caller, bool AutoSigsFlag, bool ConsecSignalsRoute)
15393 /*
15394  Sets all element values in the RouteFlashVector (member of class TRouteFlash - defined in TOneRoute, of which
15395  TOneRoute has one member called RouteFlash) from the SearchVector. TRouteFlashElement is also a class defined in
15396  TOneRoute.
15397 */
15398 {
15399  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRouteAndLCChangeValues," + AnsiString((short)AutoSigsFlag) + "," +
15400  AnsiString((short)ConsecSignalsRoute));
15401  RouteFlash.RouteFlashVector.clear();
15402  TRouteFlashElement RouteFlashElement;
15403 
15404  for(unsigned int b = 0; b < SearchVector.size(); b++)
15405  {
15406  int H = GetFixedSearchElementAt(11, b).HLoc;
15407  int V = GetFixedSearchElementAt(12, b).VLoc;
15409  RouteFlashElement.OverlayGraphic = GetModifiableSearchElementAt(6, b).GetRouteGraphicPtr(AutoSigsFlag, ConsecSignalsRoute);
15410  RouteFlashElement.HLoc = H;
15411  RouteFlashElement.VLoc = V;
15413  RouteFlash.RouteFlashVector.push_back(RouteFlashElement);
15414  }
15415  Utilities->CallLogPop(348);
15416 }
15417 
15418 // ---------------------------------------------------------------------------
15419 
15420 void TOneRoute::SetLCChangeValues(int Caller, bool ConsecSignalsRoute)
15421 {
15422  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLCChangeValues," + AnsiString((short)ConsecSignalsRoute));
15423  if(!PrefDirVector.empty())
15424  {
15425  for(TPrefDirVectorConstIterator PrefDirPtr = (PrefDirVector.end() - 1); PrefDirPtr >= PrefDirVector.begin(); PrefDirPtr--)
15426  {
15427  int H = PrefDirPtr->HLoc;
15428  int V = PrefDirPtr->VLoc;
15429  // check for any LCs that are closed to trains & set the flash values and store in the vector
15430  if(Track->IsLCAtHV(39, H, V))
15431  {
15432  if(Track->IsLCBarrierUpAtHV(0, H, V))
15433  {
15434  Track->LCChangeFlag = true;
15435  TTrack::TActiveLevelCrossing CLC; // constructor sets TrainPassed to false
15436  CLC.HLoc = H;
15437  CLC.VLoc = V;
15439  CLC.BaseElementSpeedTag = PrefDirPtr->SpeedTag;
15442  CLC.ConsecSignals = ConsecSignalsRoute;
15443  Track->SetLinkedLevelCrossingBarrierAttributes(1, H, V, 2); // set attr to 2 for changing state
15444  Track->ChangingLCVector.push_back(CLC);
15445  }
15446  }
15447  }
15448  }
15449  Utilities->CallLogPop(1948);
15450 }
15451 
15452 // ---------------------------------------------------------------------------
15453 
15455 /*
15456  Class TRouteFlash is defined in TOneRoute, which has one member called RouteFlash. This function
15457  checks first whether the OverlayPlotted flag is set and if not plots the OverlayGraphic for all
15458  elements in the RouteFlashVector, skipping any that a train is on. Finally the OverlayPlotted flag
15459  is set. The OverlayGraphic is set during TOneRoute::SetRouteAndLCChangeValues().
15460 */
15461 {
15462  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TRouteFlash::PlotRouteOverlay");
15463  if(!OverlayPlotted)
15464  {
15465  for(unsigned int x = 0; x < RouteFlashVector.size(); x++)
15466  {
15467  if(Track->TrackElementAt(123, RouteFlashVector.at(x).TrackVectorPosition).TrainIDOnElement > -1)
15468  continue;
15469  Display->PlotOutput(20, RouteFlashVector.at(x).HLoc * 16, RouteFlashVector.at(x).VLoc * 16, RouteFlashVector.at(x).OverlayGraphic);
15470  Display->Update();
15471  }
15472  OverlayPlotted = true;
15473  }
15474  Utilities->CallLogPop(349);
15475 }
15476 
15477 // ---------------------------------------------------------------------------
15478 
15480 /*
15481  Class TRouteFlash is defined in TOneRoute, which has one member called RouteFlash. This function
15482  checks first whether the OverlayPlotted flag is set and if so plots the OriginalGraphic for all
15483  elements in the RouteFlashVector, skipping any that a train is on. Finally the OverlayPlotted flag
15484  is reset. The OriginalGraphic is set during TOneRoute::SetRouteAndLCChangeValues().
15485 */
15486 {
15487  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TRouteFlash::PlotRouteOriginal");
15488  if(OverlayPlotted)
15489  {
15490  for(unsigned int x = 0; x < RouteFlashVector.size(); x++)
15491  {
15492  if(Track->TrackElementAt(124, RouteFlashVector.at(x).TrackVectorPosition).TrainIDOnElement > -1)
15493  continue;
15494  Display->PlotOutput(21, RouteFlashVector.at(x).HLoc * 16, RouteFlashVector.at(x).VLoc * 16, RouteFlashVector.at(x).OriginalGraphic);
15495  Display->Update();
15496  }
15497  OverlayPlotted = false;
15498  }
15499  Utilities->CallLogPop(350);
15500 }
15501 
15502 // ---------------------------------------------------------------------------
15503 
15504 const TOneRoute &TAllRoutes::GetFixedRouteAt(int Caller, int At) const
15505 {
15506  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFixedRouteAt," + AnsiString(At));
15507  if((At < 0) || ((unsigned int)At >= AllRoutesVector.size()))
15508  {
15509  throw Exception("Out of Range Error, vector size: " + AnsiString(AllRoutesVector.size()) + ", At: " + AnsiString(At) + " in GetFixedRouteAt");
15510  }
15511  Utilities->CallLogPop(120);
15512  return AllRoutesVector.at(At);
15513 }
15514 
15515 // ---------------------------------------------------------------------------
15516 // ---------------------------------------------------------------------------
15517 
15519 {
15520  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetModifiableRouteAt," + AnsiString(At));
15521  if((At < 0) || ((unsigned int)At >= AllRoutesVector.size()))
15522  {
15523  throw Exception("Out of Range Error, vector size: " + AnsiString(AllRoutesVector.size()) + ", At: " + AnsiString(At) + " in GetModifiableRouteAt");
15524  }
15525  Utilities->CallLogPop(121);
15526  return AllRoutesVector.at(At);
15527 }
15528 
15529 // ---------------------------------------------------------------------------
15530 
15531 void TAllRoutes::MarkAllRoutes(int Caller, TDisplay *Disp)
15532 /*
15533  Calls PrefDirMarker for all routes, with RouteCall set to identify a route call, and BuildingPrefDir false.
15534 */
15535 {
15536  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",MarkAllRoutes");
15537  for(unsigned int a = 0; a < AllRoutesSize(); a++)
15538  {
15539  GetFixedRouteAt(62, a).PrefDirMarker(7, RouteCall, false, Disp);
15540  }
15541  Utilities->CallLogPop(351);
15542 }
15543 
15544 // ---------------------------------------------------------------------------
15545 
15546 void TAllRoutes::WriteAllRoutesToImage(int Caller, Graphics::TBitmap *Bitmap)
15547 {
15548  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WriteAllRoutesToImage");
15549  for(unsigned int a = 0; a < AllRoutesSize(); a++)
15550  {
15551  GetFixedRouteAt(166, a).RouteImageMarker(0, Bitmap);
15552  }
15553  Utilities->CallLogPop(1706);
15554 }
15555 
15556 // ---------------------------------------------------------------------------
15557 
15558 bool TAllRoutes::GetAllRoutesTruncateElement(int Caller, int HLoc, int VLoc, bool ConsecSignalsRoute)
15559 /*
15560  Examines all routes and for each uses GetRouteTruncateElement to see if the element at H & V is present in
15561  that route. The ReturnFlag value indicates InRouteTrue (success), InRouteFalse (failure), or NotInRoute.
15562  Messages are given in GetRouteTruncateElement. If successful the route is truncated at and including
15563  the element that matches H & V. If ConsecSignalsRoute ensure only truncate to a signal, else prevent
15564  truncation to a crossover, bridge or points, also prevent route being left less than 2 elements in
15565  length (train length).
15566 */
15567 {
15568  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetAllRoutesTruncateElement," + AnsiString(HLoc) + "," +
15569  AnsiString(VLoc) + "," + AnsiString((short)ConsecSignalsRoute));
15570  for(unsigned int a = 0; a < AllRoutesSize(); a++)
15571  {
15572  TTruncateReturnType ReturnFlag;
15573  RouteTruncateFlag = true;
15574 // used in SetRearwardsSignalsReturnFalseForTrain (called by GetRouteTruncateElement) to skip continuation & buffer attribute change
15575  GetModifiableRouteAt(7, a).GetRouteTruncateElement(0, HLoc, VLoc, ConsecSignalsRoute, ReturnFlag);
15576  RouteTruncateFlag = false;
15577  if(ReturnFlag == NotInRoute)
15578  continue;
15579  else if(ReturnFlag == InRouteTrue)
15580  {
15581  Utilities->CallLogPop(352);
15582  return true;
15583  }
15584  else if(ReturnFlag == InRouteFalse)
15585  {
15586  Utilities->CallLogPop(353);
15587  return false;
15588  }
15589  }
15590  Utilities->CallLogPop(354);
15591  return false;
15592 }
15593 
15594 // ---------------------------------------------------------------------------
15595 
15596 bool TAllRoutes::TrackIsInARoute(int Caller, int TrackVectorPosition, int LinkPos)
15597 /*
15598  Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit)
15599  is found it returns true (for crossovers returns true whichever track the route is on), else returns false.
15600 */
15601 {
15602  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackIsInARoute," + AnsiString(TrackVectorPosition) + "," +
15603  AnsiString(LinkPos));
15604  if(TrackVectorPosition == -1) // allows for continuation entries & exits
15605  {
15606  Utilities->CallLogPop(355);
15607  return false;
15608  }
15609  THVPair Route2MultiMapKeyPair;
15610 
15611  Route2MultiMapKeyPair.first = Track->TrackElementAt(125, TrackVectorPosition).HLoc;
15612  Route2MultiMapKeyPair.second = Track->TrackElementAt(126, TrackVectorPosition).VLoc;
15613  int EntryLink, EntryLinkPos, ExitLink, ExitLinkPos;
15614  TRoute2MultiMapIterator Route2MultiMapIterator;
15615 
15616  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 0) // none found
15617  {
15618  Utilities->CallLogPop(356);
15619  return false;
15620  }
15621  if(Track->TrackElementAt(706, TrackVectorPosition).TrackType != Bridge) // if not a bridge doesn't matter which track the route is on
15622  {
15623  Utilities->CallLogPop(1422);
15624  return true;
15625  }
15626  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 1)
15627  {
15628  Route2MultiMapIterator = Route2MultiMap.find(Route2MultiMapKeyPair);
15629 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
15630 // realised after writing this that can't be points as would have been covered above, but leave anyway
15631  const TPrefDirElement &PrefDirElement1 = GetFixedRouteAt(64, Route2MultiMapIterator->second.first).GetFixedPrefDirElementAt(88,
15632  Route2MultiMapIterator->second.second);
15633  EntryLinkPos = PrefDirElement1.ELinkPos;
15634  ExitLinkPos = PrefDirElement1.XLinkPos;
15635  EntryLink = PrefDirElement1.Link[EntryLinkPos];
15636  ExitLink = PrefDirElement1.Link[ExitLinkPos];
15637  if(EntryLink == Track->TrackElementAt(127, TrackVectorPosition).Link[LinkPos])
15638  {
15639  Utilities->CallLogPop(357);
15640  return true;
15641  }
15642  if(ExitLink == Track->TrackElementAt(128, TrackVectorPosition).Link[LinkPos])
15643  {
15644  Utilities->CallLogPop(358);
15645  return true;
15646  }
15647  }
15648  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 2) // if both tracks in route then must return true
15649  {
15650  Utilities->CallLogPop(1423);
15651  return true;
15652  }
15653  Utilities->CallLogPop(363);
15654  return false; // none found
15655 }
15656 
15657 // ---------------------------------------------------------------------------
15658 
15659 TAllRoutes::TRouteType TAllRoutes::GetRouteTypeAndGraphics(int Caller, int TrackVectorPosition, int LinkPos, Graphics::TBitmap* &EXGraphicPtr,
15660  Graphics::TBitmap* &EntryDirectionGraphicPtr)
15661 /*
15662  Examines Route2MultiMap and if finds the element at TrackVectorPosition with LinkPos (can be entry or exit) returns the appropriate route
15663  type - NoRoute, NotAutoSigsRoute, or AutoSigsRoute. If element not found then NoRoute is returned. If element is in a route then the EXGraphicPtr
15664  is returned, and if either the start or end of a route then the correct EntryDirectionGraphicPtr is returned, else a transparent element is returned.
15665  Function is used in TrainUnit for retaining AutoSigsRoutes but erasing others after train passes, and for picking up the correct background graphics
15666  for replotting of AutoSigsRoutes.
15667 */
15668 {
15669  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteTypeAndGraphics," + AnsiString(TrackVectorPosition) + "," +
15670  AnsiString(LinkPos));
15671  EXGraphicPtr = RailGraphics->bmTransparentBgnd; // default value
15672  EntryDirectionGraphicPtr = RailGraphics->bmTransparentBgnd; // default value
15673  if(TrackVectorPosition == -1)
15674  {
15675  Utilities->CallLogPop(364);
15676  return NoRoute; // allows for continuation entries & exits
15677  }
15678  THVPair Route2MultiMapKeyPair;
15679 
15680  Route2MultiMapKeyPair.first = Track->TrackElementAt(133, TrackVectorPosition).HLoc;
15681  Route2MultiMapKeyPair.second = Track->TrackElementAt(134, TrackVectorPosition).VLoc;
15682  int EntryLink, EntryLinkPos, ExitLink, ExitLinkPos;
15683  TRoute2MultiMapIterator Route2MultiMapIterator;
15684 
15685  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 0)
15686  {
15687  Utilities->CallLogPop(365);
15688  return NoRoute; // none found
15689  }
15690  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 1)
15691  {
15692  Route2MultiMapIterator = Route2MultiMap.find(Route2MultiMapKeyPair);
15693 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
15694  const TPrefDirElement &PrefDirElement1 = GetFixedRouteAt(73, Route2MultiMapIterator->second.first).GetFixedPrefDirElementAt(97,
15695  Route2MultiMapIterator->second.second);
15696  EntryLinkPos = PrefDirElement1.ELinkPos;
15697  ExitLinkPos = PrefDirElement1.XLinkPos;
15698  EntryLink = PrefDirElement1.Link[EntryLinkPos];
15699  ExitLink = PrefDirElement1.Link[ExitLinkPos];
15700  if(EntryLink == Track->TrackElementAt(135, TrackVectorPosition).Link[LinkPos])
15701  {
15702  EXGraphicPtr = PrefDirElement1.EXGraphicPtr;
15703  if((Route2MultiMapIterator->second.second == 0) || (Route2MultiMapIterator->second.second == GetFixedRouteAt(74,
15704  Route2MultiMapIterator->second.first).PrefDirSize() - 1))
15705  {
15706  EntryDirectionGraphicPtr = PrefDirElement1.EntryDirectionGraphicPtr;
15707  }
15708  if(PrefDirElement1.AutoSignals)
15709  {
15710  Utilities->CallLogPop(366);
15711  return AutoSigsRoute;
15712  }
15713  else
15714  {
15715  Utilities->CallLogPop(367);
15716  return NotAutoSigsRoute;
15717  }
15718  }
15719  if(ExitLink == Track->TrackElementAt(136, TrackVectorPosition).Link[LinkPos])
15720  {
15721  EXGraphicPtr = PrefDirElement1.EXGraphicPtr;
15722  if((Route2MultiMapIterator->second.second == 0) || (Route2MultiMapIterator->second.second == GetFixedRouteAt(75,
15723  Route2MultiMapIterator->second.first).PrefDirSize() - 1))
15724  {
15725  EntryDirectionGraphicPtr = PrefDirElement1.EntryDirectionGraphicPtr;
15726  }
15727  if(PrefDirElement1.AutoSignals)
15728  {
15729  Utilities->CallLogPop(368);
15730  return AutoSigsRoute;
15731  }
15732  else
15733  {
15734  Utilities->CallLogPop(369);
15735  return NotAutoSigsRoute;
15736  }
15737  }
15738  }
15739  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 2)
15740  {
15741  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItPair;
15742  ItPair = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
15743 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
15744  const TPrefDirElement &PrefDirElement2 = GetFixedRouteAt(76, ItPair.first->second.first).GetFixedPrefDirElementAt(98, ItPair.first->second.second);
15745  EntryLinkPos = PrefDirElement2.ELinkPos;
15746  ExitLinkPos = PrefDirElement2.XLinkPos;
15747  EntryLink = PrefDirElement2.Link[EntryLinkPos];
15748  ExitLink = PrefDirElement2.Link[ExitLinkPos];
15749  if(EntryLink == Track->TrackElementAt(137, TrackVectorPosition).Link[LinkPos])
15750  {
15751  EXGraphicPtr = PrefDirElement2.EXGraphicPtr;
15752  if((ItPair.first->second.second == 0) || (ItPair.first->second.second == GetFixedRouteAt(77, ItPair.first->second.first).PrefDirSize() - 1))
15753  {
15754  EntryDirectionGraphicPtr = PrefDirElement2.EntryDirectionGraphicPtr;
15755  }
15756  if(PrefDirElement2.AutoSignals)
15757  {
15758  Utilities->CallLogPop(370);
15759  return AutoSigsRoute;
15760  }
15761  else
15762  {
15763  Utilities->CallLogPop(371);
15764  return NotAutoSigsRoute;
15765  }
15766  }
15767  if(ExitLink == Track->TrackElementAt(138, TrackVectorPosition).Link[LinkPos])
15768  {
15769  EXGraphicPtr = PrefDirElement2.EXGraphicPtr;
15770  if((ItPair.first->second.second == 0) || (ItPair.first->second.second == GetFixedRouteAt(78, ItPair.first->second.first).PrefDirSize() - 1))
15771  {
15772  EntryDirectionGraphicPtr = PrefDirElement2.EntryDirectionGraphicPtr;
15773  }
15774  if(PrefDirElement2.AutoSignals)
15775  {
15776  Utilities->CallLogPop(372);
15777  return AutoSigsRoute;
15778  }
15779  else
15780  {
15781  Utilities->CallLogPop(373);
15782  return NotAutoSigsRoute;
15783  }
15784  }
15785 
15786  ItPair.second--; // the second iterator points one past the last matching value
15787  const TPrefDirElement &PrefDirElement3 = GetFixedRouteAt(79, ItPair.second->second.first).GetFixedPrefDirElementAt(99, ItPair.second->second.second);
15788  EntryLinkPos = PrefDirElement3.ELinkPos;
15789  ExitLinkPos = PrefDirElement3.XLinkPos;
15790  EntryLink = PrefDirElement3.Link[EntryLinkPos];
15791  ExitLink = PrefDirElement3.Link[ExitLinkPos];
15792  if(EntryLink == Track->TrackElementAt(139, TrackVectorPosition).Link[LinkPos])
15793  {
15794  EXGraphicPtr = PrefDirElement3.EXGraphicPtr;
15795  if((ItPair.second->second.second == 0) || (ItPair.second->second.second == GetFixedRouteAt(80, ItPair.second->second.first).PrefDirSize() - 1))
15796  {
15797  EntryDirectionGraphicPtr = PrefDirElement3.EntryDirectionGraphicPtr;
15798  }
15799  if(PrefDirElement3.AutoSignals)
15800  {
15801  Utilities->CallLogPop(374);
15802  return AutoSigsRoute;
15803  }
15804  else
15805  {
15806  Utilities->CallLogPop(375);
15807  return NotAutoSigsRoute;
15808  }
15809  }
15810  if(ExitLink == Track->TrackElementAt(140, TrackVectorPosition).Link[LinkPos])
15811  {
15812  EXGraphicPtr = PrefDirElement3.EXGraphicPtr;
15813  if((ItPair.second->second.second == 0) || (ItPair.second->second.second == GetFixedRouteAt(81, ItPair.second->second.first).PrefDirSize() - 1))
15814  {
15815  EntryDirectionGraphicPtr = PrefDirElement3.EntryDirectionGraphicPtr;
15816  }
15817  if(PrefDirElement3.AutoSignals)
15818  {
15819  Utilities->CallLogPop(376);
15820  return AutoSigsRoute;
15821  }
15822  else
15823  {
15824  Utilities->CallLogPop(377);
15825  return NotAutoSigsRoute;
15826  }
15827  }
15828  }
15829  Utilities->CallLogPop(378);
15830  return NoRoute; // none found
15831 }
15832 
15833 // ---------------------------------------------------------------------------
15834 TAllRoutes::TRouteType TAllRoutes::GetRouteTypeAndNumber(int Caller, int TrackVectorPosition, int LinkPos, int &RouteNumber)
15835 /*
15836  Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit) is found returns the appropriate
15837  route type - NoRoute, NotAutoSigsRoute, or AutoSigsRoute and number.
15838 */
15839 {
15840  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteTypeAndNumber," + AnsiString(TrackVectorPosition) + "," +
15841  AnsiString(LinkPos));
15842  if(TrackVectorPosition == -1)
15843  {
15844  RouteNumber = -1;
15845  Utilities->CallLogPop(379);
15846  return NoRoute; // allows for continuation & buffer entries & exits
15847  }
15848  THVPair Route2MultiMapKeyPair;
15849 
15850  Route2MultiMapKeyPair.first = Track->TrackElementAt(141, TrackVectorPosition).HLoc;
15851  Route2MultiMapKeyPair.second = Track->TrackElementAt(142, TrackVectorPosition).VLoc;
15852  int EntryLink, EntryLinkPos, ExitLink, ExitLinkPos;
15853  TRoute2MultiMapIterator Route2MultiMapIterator;
15854 
15855  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 0)
15856  {
15857  RouteNumber = -1;
15858  Utilities->CallLogPop(380);
15859  return NoRoute; // none found
15860  }
15861  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 1)
15862  {
15863  Route2MultiMapIterator = Route2MultiMap.find(Route2MultiMapKeyPair);
15864 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
15865  const TPrefDirElement &PrefDirElement1 = GetFixedRouteAt(82, Route2MultiMapIterator->second.first).GetFixedPrefDirElementAt(100,
15866  Route2MultiMapIterator->second.second);
15867  EntryLinkPos = PrefDirElement1.ELinkPos;
15868  ExitLinkPos = PrefDirElement1.XLinkPos;
15869  EntryLink = PrefDirElement1.Link[EntryLinkPos];
15870  ExitLink = PrefDirElement1.Link[ExitLinkPos];
15871  if(EntryLink == Track->TrackElementAt(143, TrackVectorPosition).Link[LinkPos])
15872  {
15873  RouteNumber = Route2MultiMapIterator->second.first;
15874  if(PrefDirElement1.AutoSignals)
15875  {
15876  Utilities->CallLogPop(381);
15877  return AutoSigsRoute;
15878  }
15879  else
15880  {
15881  Utilities->CallLogPop(382);
15882  return NotAutoSigsRoute;
15883  }
15884  }
15885  if(ExitLink == Track->TrackElementAt(144, TrackVectorPosition).Link[LinkPos])
15886  {
15887  RouteNumber = Route2MultiMapIterator->second.first;
15888  if(PrefDirElement1.AutoSignals)
15889  {
15890  Utilities->CallLogPop(383);
15891  return AutoSigsRoute;
15892  }
15893  else
15894  {
15895  Utilities->CallLogPop(384);
15896  return NotAutoSigsRoute;
15897  }
15898  }
15899  }
15900  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 2)
15901  {
15902  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItPair;
15903  ItPair = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
15904 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
15905  const TPrefDirElement &PrefDirElement2 = GetFixedRouteAt(83, ItPair.first->second.first).GetFixedPrefDirElementAt(101, ItPair.first->second.second);
15906  EntryLinkPos = PrefDirElement2.ELinkPos;
15907  ExitLinkPos = PrefDirElement2.XLinkPos;
15908  EntryLink = PrefDirElement2.Link[EntryLinkPos];
15909  ExitLink = PrefDirElement2.Link[ExitLinkPos];
15910  if(EntryLink == Track->TrackElementAt(145, TrackVectorPosition).Link[LinkPos])
15911  {
15912  RouteNumber = ItPair.first->second.first;
15913  if(PrefDirElement2.AutoSignals)
15914  {
15915  Utilities->CallLogPop(385);
15916  return AutoSigsRoute;
15917  }
15918  else
15919  {
15920  Utilities->CallLogPop(386);
15921  return NotAutoSigsRoute;
15922  }
15923  }
15924  if(ExitLink == Track->TrackElementAt(146, TrackVectorPosition).Link[LinkPos])
15925  {
15926  RouteNumber = ItPair.first->second.first;
15927  if(PrefDirElement2.AutoSignals)
15928  {
15929  Utilities->CallLogPop(387);
15930  return AutoSigsRoute;
15931  }
15932  else
15933  {
15934  Utilities->CallLogPop(388);
15935  return NotAutoSigsRoute;
15936  }
15937  }
15938 
15939  ItPair.second--; // the second iterator points one past the last matching value
15940  const TPrefDirElement &PrefDirElement3 = GetFixedRouteAt(84, ItPair.second->second.first).GetFixedPrefDirElementAt(102, ItPair.second->second.second);
15941  EntryLinkPos = PrefDirElement3.ELinkPos;
15942  ExitLinkPos = PrefDirElement3.XLinkPos;
15943  EntryLink = PrefDirElement3.Link[EntryLinkPos];
15944  ExitLink = PrefDirElement3.Link[ExitLinkPos];
15945  if(EntryLink == Track->TrackElementAt(147, TrackVectorPosition).Link[LinkPos])
15946  {
15947  RouteNumber = ItPair.second->second.first;
15948  if(PrefDirElement3.AutoSignals)
15949  {
15950  Utilities->CallLogPop(389);
15951  return AutoSigsRoute;
15952  }
15953  else
15954  {
15955  Utilities->CallLogPop(390);
15956  return NotAutoSigsRoute;
15957  }
15958  }
15959  if(ExitLink == Track->TrackElementAt(148, TrackVectorPosition).Link[LinkPos])
15960  {
15961  RouteNumber = ItPair.second->second.first;
15962  if(PrefDirElement3.AutoSignals)
15963  {
15964  Utilities->CallLogPop(391);
15965  return AutoSigsRoute;
15966  }
15967  else
15968  {
15969  Utilities->CallLogPop(392);
15970  return NotAutoSigsRoute;
15971  }
15972  }
15973  }
15974  RouteNumber = -1;
15975  Utilities->CallLogPop(393);
15976  return NoRoute; // none found
15977 }
15978 
15979 // ---------------------------------------------------------------------------
15980 
15981 void TAllRoutes::StoreOneRoute(int Caller, TOneRoute *Route)
15982 /*
15983  A new (empty apart from RouteID) TOneRoute is added to the AllRoutesVector, which, since it is the last to be added, will have
15984  a RouteNumber of AllRoutesSize() - 1. Then each element of the new route is added in turn using AddRouteElement,
15985  which uses HLoc, VLoc, ELink and RouteNumber to provide the information necessary to insert it into both PrefDirVector
15986  and Route2MultiMap.
15987 */
15988 {
15989  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",StoreOneRoute");
15990  TOneRoute EmptyRoute;
15991 
15992  EmptyRoute.RouteID = NextRouteID;
15993  NextRouteID++;
15994 
15995  AllRoutesVector.push_back(EmptyRoute); // to create a new route vector entry
15996  for(unsigned int x = 0; x < Route->PrefDirSize(); x++)
15997  {
15998  AddRouteElement(0, Route->GetFixedPrefDirElementAt(127, x).HLoc, Route->GetFixedPrefDirElementAt(128, x).VLoc,
15999  Route->GetFixedPrefDirElementAt(129, x).GetELink(), AllRoutesSize() - 1, Route->GetFixedPrefDirElementAt(130, x));
16000  }
16001  int FirstVecPos = Route->GetFixedPrefDirElementAt(199, 0).TrackVectorPosition;
16002  int LastVecPos = Route->GetFixedPrefDirElementAt(200, (Route->PrefDirSize()) - 1).TrackVectorPosition;
16003 
16004  TrainController->LogEvent("StoreOneRoute," + AnsiString(EmptyRoute.RouteID) + "," + AnsiString(FirstVecPos) + "," + AnsiString(LastVecPos));
16005  Utilities->CallLogPop(394);
16006 }
16007 
16008 // ---------------------------------------------------------------------------
16009 
16011 /*
16012  A new (empty apart from RouteID) TOneRoute is added to the AllRoutesVector after a session load. For this the RouteID
16013  that is already in Route is used.
16014 */
16015 {
16016  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",StoreOneRouteAfterSessionLoad");
16017  TOneRoute EmptyRoute;
16018 
16019  EmptyRoute.RouteID = Route->RouteID;
16020 
16021  AllRoutesVector.push_back(EmptyRoute); // to create a new route vector entry
16022  for(unsigned int x = 0; x < Route->PrefDirSize(); x++)
16023  {
16024  AddRouteElement(3, Route->GetFixedPrefDirElementAt(189, x).HLoc, Route->GetFixedPrefDirElementAt(190, x).VLoc,
16025  Route->GetFixedPrefDirElementAt(191, x).GetELink(), AllRoutesSize() - 1, Route->GetFixedPrefDirElementAt(192, x));
16026  }
16027  Utilities->CallLogPop(1579);
16028 }
16029 
16030 // ---------------------------------------------------------------------------
16031 
16032 void TAllRoutes::ClearRouteDuringRouteBuildingAt(int Caller, int RouteNumber)
16033 /*
16034  When attaching a new route section to an existing route, it is sometimes necessary to erase the
16035  original route and create a new composite route. This function Erases all elements in the route
16036  at RouteNumber using TAllRoutes->RemoveRouteElement to clear elements from Route2MultiMap and
16037  from the PrefDirVector. Since all elements for the route are removed RemoveRouteElement also
16038  clears the Route from AllRoutesVector. Route numbers are decremented in the map for route numbers
16039  that are greater than the route number that is removed. The LockedRouteVector as also searched
16040  and if any relate to the route that has been cleared they are erased too, but the fact that one
16041  has been found is recorded so that it can be re-established later.
16042 */
16043 {
16044  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ClearRouteDuringRouteBuildingAt," + AnsiString(RouteNumber));
16045  THVPair Route2MultiMapKeyPair;
16046  TRoute2MultiMapEntry Route2MultiMapEntry;
16047  TRoute2MultiMapIterator Route2MultiMapIterator;
16048 
16049 // need to check LockedVector first, and erase it if it's the route to be cleared, and to reinstate it as a new locked route with the same
16050 // values (except RouteNumber) when the new route is established (in ConvertAndAdd...).
16051 // If clear all route elements first then when the last is cleared the LockedVector.RouteNumber values are decremented if they are higher
16052 // then the cleared route number (by RemoveRouteElement), and one of the new values may be the same number as the old cleared route number.
16053 // If so the locked route is removed from the locked vector and is lost.
16054  LockedRouteTruncateTrackVectorPosition = 0;
16055  LockedRouteLastTrackVectorPosition = 0;
16056  LockedRouteLastXLinkPos = 0;
16057  LockedRouteLockStartTime = TDateTime(0);
16058  if(!LockedRouteVector.empty())
16059  {
16060  for(TLockedRouteVectorIterator LRVIT = LockedRouteVector.begin(); LRVIT < LockedRouteVector.end(); LRVIT++)
16061  {
16062  if(LRVIT->RouteNumber == RouteNumber)
16063  {
16064  LockedRouteTruncateTrackVectorPosition = LRVIT->TruncateTrackVectorPosition;
16065  LockedRouteLastTrackVectorPosition = LRVIT->LastTrackVectorPosition;
16066  LockedRouteLastXLinkPos = LRVIT->LastXLinkPos;
16067  LockedRouteLockStartTime = LRVIT->LockStartTime;
16068  LockedRouteFoundDuringRouteBuilding = true;
16069  LockedRouteVector.erase(LRVIT);
16070  }
16071  }
16072  }
16073 
16074  for(int x = (AllRoutes->GetFixedRouteAt(109, RouteNumber).PrefDirSize()) - 1; x >= 0; x--)
16075  {
16076  TPrefDirElement PrefDirElement = AllRoutes->GetFixedRouteAt(110, RouteNumber).GetFixedPrefDirElementAt(131, x);
16077  AllRoutes->RemoveRouteElement(7, PrefDirElement.HLoc, PrefDirElement.VLoc, PrefDirElement.GetELink());
16078  }
16079  Utilities->CallLogPop(395);
16080 }
16081 
16082 // ---------------------------------------------------------------------------
16083 
16085  TRoute2MultiMapIterator &Route2MultiMapIterator)
16086 /*
16087  Examines Route2MultiMap and returns a TRouteElementPair if one is found with the passed values of H, V and ELink.
16088  Also returned as a reference is an iterator to the found element in the map to assist in erasing it. Called by
16089  TAllRoutes::RemoveRouteElement(int Caller, int HLoc, int VLoc, int ELink). Note that only need ELink (as well as H & V) to
16090  identify uniquely, since only bridges can have two routes on them & their track ELinks are always different. Messages
16091  are given for failure.
16092 */
16093 {
16094  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindRoutePairFromRoute2MultiMap," + AnsiString(HLoc) + "," +
16095  AnsiString(VLoc) + "," + AnsiString(ELink));
16096  TRouteElementPair ReturnPair;
16097 
16098  ReturnPair.first = -1;
16099  ReturnPair.second = 0;
16100  THVPair Route2MultiMapKeyPair;
16101 
16102  Route2MultiMapKeyPair.first = HLoc;
16103  Route2MultiMapKeyPair.second = VLoc;
16104  TRoute2MultiMapEntry Route2MultiMapEntry;
16105 
16106  Route2MultiMapEntry.first = Route2MultiMapKeyPair;
16107  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItPair;
16108 
16109  ItPair = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
16110  Route2MultiMapIterator = ItPair.first;
16111 
16112  if(ItPair.first == ItPair.second)
16113  {
16114  throw Exception("Failed to find Route2MultiMap element at HLoc = " + (AnsiString)HLoc + " VLoc = " + (AnsiString)VLoc);
16115  }
16116 
16117  if(GetFixedRouteAt(111, ItPair.first->second.first).GetFixedPrefDirElementAt(132, ItPair.first->second.second).GetELink() == ELink)
16118  {
16119  ReturnPair.first = ItPair.first->second.first;
16120  ReturnPair.second = ItPair.first->second.second;
16121  Route2MultiMapIterator = ItPair.first;
16122  Utilities->CallLogPop(396);
16123  return ReturnPair;
16124  }
16125  ItPair.first++;
16126  if(ItPair.first == ItPair.second)
16127  {
16128  throw Exception("Found Route2MultiMap element at HLoc = " + (AnsiString)HLoc + " VLoc = " + (AnsiString)VLoc + " but failed to find required element");
16129  }
16130  if(GetFixedRouteAt(112, ItPair.first->second.first).GetFixedPrefDirElementAt(133, ItPair.first->second.second).GetELink() == ELink)
16131  {
16132  ReturnPair.first = ItPair.first->second.first;
16133  ReturnPair.second = ItPair.first->second.second;
16134  Route2MultiMapIterator = ItPair.first;
16135  Utilities->CallLogPop(397);
16136  return ReturnPair;
16137  }
16138  Utilities->CallLogPop(398);
16139  return ReturnPair;
16140 }
16141 
16142 // ---------------------------------------------------------------------------
16143 
16144 bool TAllRoutes::FindRouteNumberFromRoute2MultiMapNoErrors(int Caller, int HLoc, int VLoc, int ELink, int &RouteNumber) // new at v1.2.0
16145 /*
16146  Similar to above but returns a bool and no errors are reported for no route or element at H&V etc.
16147  Examines Route2MultiMap and returns true if oa route is found with the passed values of H, V and ELink.
16148  RouteNumber (route position in AllRoutes vector is returned as a reference.
16149  Called by TTrain::CheckAndCancelRouteForWrongEndEntry. Note that only need ELink (as well as H & V) to
16150  identify uniquely, since only bridges can have two routes on them & their track ELinks are always different.
16151 */
16152 {
16153  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindRouteNumberFromRoute2MultiMapNoErrors," + AnsiString(HLoc) + "," +
16154  AnsiString(VLoc) + "," + AnsiString(ELink));
16155  THVPair Route2MultiMapKeyPair;
16156 
16157  Route2MultiMapKeyPair.first = HLoc;
16158  Route2MultiMapKeyPair.second = VLoc;
16159  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItPair;
16160 
16161  ItPair = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
16162 
16163  if(ItPair.first == ItPair.second)
16164  {
16165  RouteNumber = -1;
16166  Utilities->CallLogPop(2032);
16167  return false;
16168  }
16169 
16170  if(GetFixedRouteAt(205, ItPair.first->second.first).GetFixedPrefDirElementAt(241, ItPair.first->second.second).GetELink() == ELink)
16171  {
16172  RouteNumber = ItPair.first->second.first;
16173  Utilities->CallLogPop(2033);
16174  return true;
16175  }
16176 
16177  ItPair.first++;
16178 
16179  if(ItPair.first == ItPair.second)
16180  {
16181  RouteNumber = -1;
16182  Utilities->CallLogPop(2034);
16183  return false;
16184  }
16185 
16186  if(GetFixedRouteAt(206, ItPair.first->second.first).GetFixedPrefDirElementAt(242, ItPair.first->second.second).GetELink() == ELink)
16187  {
16188  RouteNumber = ItPair.first->second.first;
16189  Utilities->CallLogPop(2035);
16190  return true;
16191  }
16192  RouteNumber = -1;
16193  Utilities->CallLogPop(2036);
16194  return false;
16195 }
16196 
16197 // ---------------------------------------------------------------------------
16198 
16199 void TAllRoutes::Route2MultiMapInsert(int Caller, int HLoc, int VLoc, int ELinkIn, int RouteNumber, unsigned int RouteElementNumber)
16200 /*
16201  Elink needed in case it's a bridge, & need to know whether the found element is on this route or not. First check if an
16202  entry in the map already exists at H & V, and if so check that it's a bridge with existing route on other track.
16203  That being so insert the new element. If it's not a bridge, or the route has the same ELink value as the element to
16204  be inserted, give appropriate messages. If there isn't an element at H & V already in the map insert it.
16205  Called by TAllRoutes::AddRouteElement.
16206 */
16207 {
16208  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",Route2MultiMapInsert," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
16209  "," + AnsiString(ELinkIn) + "," + AnsiString(RouteNumber) + "," + AnsiString(RouteElementNumber));
16210  THVPair Route2MultiMapKeyPair;
16211 
16212  Route2MultiMapKeyPair.first = HLoc;
16213  Route2MultiMapKeyPair.second = VLoc;
16214  TRoute2MultiMapEntry Route2MultiMapEntry;
16215 
16216  Route2MultiMapEntry.first = Route2MultiMapKeyPair;
16217  TRouteElementPair RouteElementPair;
16218 
16219  RouteElementPair.first = RouteNumber;
16220  RouteElementPair.second = RouteElementNumber;
16221  Route2MultiMapEntry.second = RouteElementPair;
16222 
16223  if(Route2MultiMap.find(Route2MultiMapKeyPair) != Route2MultiMap.end())
16224  // true for element at H&V already included in map, has to be a bridge with existing route on opposite track to be valid
16225  {
16226  if(GetFixedRouteAt(113, Route2MultiMap.find(Route2MultiMapKeyPair)->second.first).GetFixedPrefDirElementAt(134,
16227  Route2MultiMap.find(Route2MultiMapKeyPair)->second.second).GetELink() != ELinkIn)
16228  // element already at H&V has different ELink to element to be inserted, so must be a bridge with existing route on opposite treack
16229  {
16230  if(GetFixedRouteAt(114, Route2MultiMap.find(Route2MultiMapKeyPair)->second.first).GetFixedPrefDirElementAt(135,
16231  Route2MultiMap.find(Route2MultiMapKeyPair)->second.second).TrackType != Bridge)
16232  {
16233  throw Exception("Error, bridge expected in Route2MultiMapInsert but not, at HLoc=" + AnsiString(HLoc) + " VLoc=" + AnsiString(VLoc));
16234  }
16235  Route2MultiMap.insert(Route2MultiMapEntry); // insert bridge into map again but now with the new track as part of required route
16236  }
16237  else
16238  // same ELink so have an error
16239  {
16240  throw Exception("Error, route map entry found in Route2MultiMapInsert at HLoc=" + AnsiString(HLoc) + " VLoc=" + AnsiString(VLoc));
16241  }
16242  }
16243  else
16244  Route2MultiMap.insert(Route2MultiMapEntry);
16245 // element at H&V not found in map so insert it
16246  Utilities->CallLogPop(399);
16247 }
16248 
16249 // ---------------------------------------------------------------------------
16250 
16252 /*
16253  Retrieve up to two TRouteElementPair entries from Route2MultiMap at H & V, the first as a function return
16254  and the second in the reference SecondPair. If there's only one then it's the function return
16255 */
16256 {
16257  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteElementDataFromRoute2MultiMap," + AnsiString(HLoc) + "," +
16258  AnsiString(VLoc));
16260 
16261  TempPair.first = -1;
16262  TempPair.second = 0;
16263  SecondPair = TempPair;
16264  TRoute2MultiMapIterator Route2MultiMapIterator;
16265  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItRange;
16266  THVPair Route2MultiMapKeyPair;
16267 
16268  Route2MultiMapKeyPair.first = HLoc;
16269  Route2MultiMapKeyPair.second = VLoc;
16270  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 0)
16271  {
16272  Utilities->CallLogPop(400);
16273  return TempPair;
16274  }
16275  else if(Route2MultiMap.count(Route2MultiMapKeyPair) == 1)
16276  {
16277  Route2MultiMapIterator = Route2MultiMap.find(Route2MultiMapKeyPair);
16278  Utilities->CallLogPop(401);
16279  return Route2MultiMapIterator->second;
16280  }
16281  else if(Route2MultiMap.count(Route2MultiMapKeyPair) == 2)
16282  {
16283  ItRange = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
16284  TempPair = ItRange.first->second;
16285  SecondPair = (--ItRange.second)->second; // 2nd iterator points past the last value
16286  Utilities->CallLogPop(402);
16287  return TempPair;
16288  }
16289  Utilities->CallLogPop(403);
16290  return TempPair;
16291 }
16292 
16293 // ---------------------------------------------------------------------------
16294 
16295 void TAllRoutes::CheckMapAndRoutes(int Caller) // test
16296 /*
16297  Checks equivalence for each route between entries in PrefDirVector and those in Route2MultiMap, and also that the size
16298  of the multimap and the sum of the sizes of all PrefDirVectors is the same.
16299 */
16300 {
16301  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckMapAndRoutes");
16302  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
16303  {
16304  for(unsigned int b = 0; b < AllRoutes->GetFixedRouteAt(115, a).PrefDirSize(); b++)
16305  {
16306  TPrefDirElement CheckElement = AllRoutes->GetFixedRouteAt(116, a).GetFixedPrefDirElementAt(136, b);
16307  TAllRoutes::TRouteElementPair SecondPair;
16308  TRouteElementPair RouteElementPair = GetRouteElementDataFromRoute2MultiMap(8, CheckElement.HLoc, CheckElement.VLoc, SecondPair);
16309  if(RouteElementPair.first == -1)
16310  // failed to find element in multimap
16311  {
16312  throw Exception("CheckMapAndRoutes Error - failed to find HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" + (AnsiString)CheckElement.VLoc +
16313  " in Route2MultiMap, Caller=" + (AnsiString)Caller);
16314  }
16315  if((RouteElementPair.first != (int)a) && (SecondPair.first != (int)a))
16316  // neither pair has expected route number
16317  {
16318  throw Exception("CheckMapAndRoutes Error - RouteNumber failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
16319  (AnsiString)CheckElement.VLoc + " Map value=" + (AnsiString)RouteElementPair.first + " Route value=" + (AnsiString)a + " Caller=" +
16320  (AnsiString)Caller);
16321  }
16322  if(((RouteElementPair.first != (int)a) || (RouteElementPair.second != b)) && ((SecondPair.first != (int)a) || (SecondPair.second != b)))
16323  // need one of pairs to match both RouteNumber and RouteElementNumber or fails
16324  {
16325  throw Exception("CheckMapAndRoutes Error - PrefDirVectorNumber failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
16326  (AnsiString)CheckElement.VLoc + " 1st Map value RouteNum/ElementNum =" + (AnsiString)RouteElementPair.first + "/" +
16327  (AnsiString)RouteElementPair.second + " 2nd Map value =" + (AnsiString)SecondPair.first + "/" + (AnsiString)SecondPair.second +
16328  " Route value=" + (AnsiString)a + "/" + (AnsiString)b + " Caller=" + (AnsiString)Caller);
16329  }
16330  }
16331  }
16332  unsigned int SizeVal = 0;
16333 
16334 // check map and sum of route sizes match
16335  for(unsigned int a = 0; a < AllRoutesSize(); a++)
16336  {
16337  SizeVal += GetFixedRouteAt(117, a).PrefDirSize();
16338  }
16339  if(SizeVal != Route2MultiMap.size())
16340  {
16341  throw Exception("CheckMapAndRoutes Error - Map Size=" + (AnsiString)Route2MultiMap.size() + " RouteSize=" + (AnsiString)SizeVal + " Caller=" +
16342  (AnsiString)Caller);
16343  }
16344  Utilities->CallLogPop(404);
16345  return;
16346 }
16347 
16348 // ---------------------------------------------------------------------------
16349 
16350 void TAllRoutes::DecrementRouteNumbersInRoute2MultiMap(int Caller, int RouteNumber)
16351 /*
16352  After a route has been erased from AllRoutesVector and its entries from Route2MultiMap, this
16353  function examines all the remaining entries in Route2MultiMap to see if their RouteNumbers
16354  exceed that for the erased route. Where this is so the RouteNumber is decremented.
16355 */
16356 {
16357  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementRouteNumbersInRoute2MultiMap," + AnsiString(RouteNumber));
16358  if(!Route2MultiMap.empty())
16359  {
16360  for(TRoute2MultiMapIterator Route2MultiMapIterator = Route2MultiMap.begin(); Route2MultiMapIterator != Route2MultiMap.end(); Route2MultiMapIterator++)
16361  {
16362  if(Route2MultiMapIterator->second.first > RouteNumber)
16363  Route2MultiMapIterator->second.first--;
16364  }
16365  }
16366  Utilities->CallLogPop(405);
16367 }
16368 
16369 // ---------------------------------------------------------------------------
16370 
16371 void TAllRoutes::DecrementRouteElementNumbersInRoute2MultiMap(int Caller, int RouteNumber, unsigned int ErasedElementNumber)
16372 /*
16373  After a route element has been erased from the relevant PrefDirVector and from Route2MultiMap, this
16374  function examines all the remaining entries in Route2MultiMap with the same RouteNumber as that
16375  for the erased element. Where a RouteElementNumber exceeds that for the erased element it is decremented.
16376 */
16377 {
16378  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementRouteElementNumbersInRoute2MultiMap," +
16379  AnsiString(RouteNumber) + "," + AnsiString(ErasedElementNumber));
16380  if(!Route2MultiMap.empty())
16381  {
16382  for(TRoute2MultiMapIterator Route2MultiMapIterator = Route2MultiMap.begin(); Route2MultiMapIterator != Route2MultiMap.end(); Route2MultiMapIterator++)
16383  {
16384  if((Route2MultiMapIterator->second.first == RouteNumber) && (Route2MultiMapIterator->second.second > ErasedElementNumber))
16385  Route2MultiMapIterator->second.second--;
16386  }
16387  }
16388  Utilities->CallLogPop(406);
16389 }
16390 
16391 // ---------------------------------------------------------------------------
16392 
16393 void TAllRoutes::RemoveRouteElement(int Caller, int HLoc, int VLoc, int ELink)
16394 /*
16395  Erases the route element from Route2MultiMap and from the PrefDirVector.
16396  If there are no elements left in the PrefDirVector the route is cleared from AllRoutesVector. Route element numbers in the map are
16397  decremented if they are greater than the element number removed, and if the entire route is removed
16398  then the route numbers are also decremented in the map for route numbers that are greater than the route
16399  number that is removed.
16400 */
16401 {
16402  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RemoveRouteElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
16403  AnsiString(ELink));
16404  TRouteElementPair RequiredRoutePair; // RouteNumber & RouteElementNumber
16405  TRoute2MultiMapIterator Route2MultiMapIterator;
16406 
16407  RequiredRoutePair = FindRoutePairFromRoute2MultiMap(0, HLoc, VLoc, ELink, Route2MultiMapIterator);
16408  if(RequiredRoutePair.first == -1)
16409  {
16410  throw Exception("Failed to find route element in RemoveRouteElement");
16411  }
16412  Route2MultiMap.erase(Route2MultiMapIterator);
16413  DecrementRouteElementNumbersInRoute2MultiMap(0, RequiredRoutePair.first, RequiredRoutePair.second);
16414 
16415 // even though element has been erased from the routemap, RequiredRoutePair still contains the element values
16416  TPrefDirElement LockedRouteElement, PrefDirElement = GetFixedRouteAt(118, RequiredRoutePair.first).GetFixedPrefDirElementAt(137, RequiredRoutePair.second);
16417 
16418  if(Track->TrackElementAt(157, PrefDirElement.TrackVectorPosition).Config[PrefDirElement.XLinkPos] == Signal)
16419  {
16420  Track->TrackElementAt(158, PrefDirElement.TrackVectorPosition).Attribute = 0; // change forward signals back to red
16421  }
16422 
16423 // don't need the section below (a) because when a train removes elements from the front of a locked route, there is a test in
16424 // ApproachLocking to determine whether the element immediately nearer the start of the route to the element being removed is still
16425 // present, and of not the element removal stops; and (b) because it never worked anyway! - IsElementInLockedRoute.... uses Route2MultiMap
16426 // to check if a route element is present, and the element has already been removed from the map - see above.
16427 
16428 // before erase the element check if it's in a locked route, and if so change the TruncateTrackVectorPosition to the next valid (XLinkPos] element position
16429 /*
16430  int LockedVectorNumber = -1;
16431  if(IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(5, PrefDirElement.TrackVectorPosition, PrefDirElement.XLinkPos, LockedRouteElement, LockedVectorNumber))
16432  {
16433  LockedRouteVector.at(LockedVectorNumber).TruncateTrackVectorPosition = PrefDirElement.Conn[PrefDirElement.XLinkPos];
16434  }
16435 */
16436 
16437 // erase element from route
16438  GetModifiableRouteAt(8, RequiredRoutePair.first).EraseRouteElementAt(&(GetModifiableRouteAt(9, RequiredRoutePair.first).GetModifiablePrefDirElementAt(1,
16439  RequiredRoutePair.second)));
16440 // CheckMapAndRoutes();//test - drop - tested below
16441 
16442 // remove ContinuationAutoSig route if element is in one since if any part of it is truncated the continuation exit will be removed - must
16443 // be so as continuation exit is at the end of the route, and truncation is from the end
16445  {
16447  for(AutoSigVectorIT = TrainController->ContinuationAutoSigVector.end() - 1; AutoSigVectorIT >= TrainController->ContinuationAutoSigVector.begin();
16448  AutoSigVectorIT--)
16449  {
16450  if(AutoSigVectorIT->RouteNumber == RequiredRoutePair.first)
16451  {
16452  TrainController->ContinuationAutoSigVector.erase(AutoSigVectorIT);
16453  }
16454  }
16455  }
16456 
16457 // now if last element from a route was removed need to remove the route from the route vector and from the LockedRouteVector if exists,
16458 // and adjust all the corresponding route numbers
16459  if(GetModifiableRouteAt(10, RequiredRoutePair.first).PrefDirSize() == 0)
16460  {
16461  TrainController->LogEvent("RouteRemoved," + AnsiString(GetFixedRouteAt(189, RequiredRoutePair.first).RouteID));
16462  AllRoutesVector.erase(AllRoutesVector.begin() + RequiredRoutePair.first);
16463  DecrementRouteNumbersInRoute2MultiMap(0, RequiredRoutePair.first);
16464 
16465 /* drop this: LockedVectorNumber was supposed to be determined from the above section that has been dropped, so this doesn't work
16466  It isn't needed anyway as a check is made after the Locked route timeout as to whether the end element is in a route or not, and if not
16467  it is erased then - see TInterface::ApproachLocking
16468 
16469  if(LockedVectorNumber > -1)
16470  {
16471  LockedRouteVector.erase(LockedRouteVector.begin() + LockedVectorNumber);
16472  }
16473 */
16474  // decrement route numbers in the locked route vector whether or not this route is a locked route
16475  if(!LockedRouteVector.empty())
16476  {
16477  for(TLockedRouteVectorIterator LRVIT = LockedRouteVector.begin(); LRVIT < LockedRouteVector.end(); LRVIT++)
16478  {
16479  if(LRVIT->RouteNumber > RequiredRoutePair.first)
16480  {
16481  LRVIT->RouteNumber--;
16482  }
16483  }
16484  }
16485 
16487  {
16489  for(AutoSigVectorIT = TrainController->ContinuationAutoSigVector.end() - 1; AutoSigVectorIT >= TrainController->ContinuationAutoSigVector.begin();
16490  AutoSigVectorIT--)
16491  {
16492  if(AutoSigVectorIT->RouteNumber > RequiredRoutePair.first)
16493  AutoSigVectorIT->RouteNumber--;
16494  }
16495  }
16496  }
16497  CheckMapAndRoutes(7); // test
16498  Utilities->CallLogPop(407);
16499 }
16500 
16501 // ---------------------------------------------------------------------------
16502 
16503 void TAllRoutes::AddRouteElement(int Caller, int HLoc, int VLoc, int ELink, int RouteNumber, TPrefDirElement RouteElement)
16504 /*
16505  A single TPrefDirElement is added to both PrefDirVector (for the route at RouteNumber) and Route2MultiMap.
16506  Called from TAllRoutes::StoreOneRoute. Note that the IsARoute boolean variable is set in StoreRouteElementInPrefDirVector
16507  since that catches all route elements wherever created
16508 */
16509 {
16510  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AddRouteElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
16511  AnsiString(ELink) + "," + AnsiString(RouteNumber) + "," + RouteElement.LogPrefDir());
16512  GetModifiableRouteAt(11, RouteNumber).StoreRouteElementInPrefDirVector(RouteElement);
16513  Route2MultiMapInsert(0, HLoc, VLoc, ELink, RouteNumber, GetModifiableRouteAt(12, RouteNumber).PrefDirSize() - 1);
16514  Utilities->CallLogPop(408);
16515 }
16516 
16517 // ---------------------------------------------------------------------------
16518 
16519 void TAllRoutes::SetTrailingSignalsOnAutoSigsRoute(int Caller, int TrackVectorPosition, int XLinkPos)
16520 /*
16521  Enter with signal at TrackVectorElement already set to red by the passing train.
16522  Identify the route that the TrackVectorPosition is in, carry out validity checks, then call SetAllRearwardsSignals to set signals
16523  in this route and all linked rearwards routes, unless find a train (a) in the current route, in which case the signals behind it are
16524  set (and behind any other trains in the current route), but only within the current route; or (b) in a linked rear route, in which
16525  case the function sets no further signals.
16526 */
16527 {
16528  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetTrailingSignalsOnAutoSigsRoute," + AnsiString(TrackVectorPosition) +
16529  "," + AnsiString(XLinkPos));
16530  TRouteElementPair RouteElementPair, SecondPair, RequiredPair;
16531  TTrackElement TE = Track->TrackElementAt(159, TrackVectorPosition);
16532 
16533  RouteElementPair = GetRouteElementDataFromRoute2MultiMap(9, TE.HLoc, TE.VLoc, SecondPair);
16534  if(RouteElementPair.first == -1)
16535  {
16536  throw Exception("Error, failed to find element in SetTrailingSignalsOnAutoSigsRoute - 1");
16537  }
16538  TPrefDirElement RouteElement = GetFixedRouteAt(119, RouteElementPair.first).GetFixedPrefDirElementAt(138, RouteElementPair.second);
16539 
16540  RequiredPair = RouteElementPair;
16541  if(RouteElement.XLinkPos != XLinkPos)
16542  {
16543  if(SecondPair.first != -1)
16544  {
16545  RouteElement = GetFixedRouteAt(120, SecondPair.first).GetFixedPrefDirElementAt(139, SecondPair.second);
16546  RequiredPair = SecondPair;
16547  if(RouteElement.XLinkPos != XLinkPos)
16548  {
16549  throw Exception("Failed to find element in route in SetTrailingSignalsOnAutoSigsRoute - 2");
16550  }
16551  }
16552  else
16553  {
16554  throw Exception("Failed to find element in route in SetTrailingSignalsOnAutoSigsRoute - 3");
16555  }
16556  }
16557 
16558 // new function
16559  SetAllRearwardsSignals(5, 0, RequiredPair.first, RequiredPair.second);
16560  Utilities->CallLogPop(409);
16561 }
16562 
16563 // ---------------------------------------------------------------------------
16564 
16565 void TAllRoutes::SetTrailingSignalsOnContinuationRoute(int Caller, int RouteNumber, int AccessNumber)
16566 /*
16567  This is called by the InterfaceUnit at intervals based on entries in the ContinuationAutoSigVector in TrainController to set signals on
16568  the AutoSigsRoute to correspond to a train having exited the route at a continuation, and passing further signals (outside the simulated
16569  railway). Initially the last passed signal will be red, then at the first call it will change to yellow and earlier signals will change
16570  accordingly, then double yellow, then green. There are only 3 calls in all for any given route, and the AccessNumber changes from 0 to 1
16571  to 2 for successive calls.
16572  Initially Attribute is set to AccessNumber + 1 to correspond to the first signal attribute to be set, then a number of validity checks
16573  are carried out on RouteNumber. Then SetAllRearwardsSignals is called to set signals in this route and all linked rearwards routes,
16574  unless find a train (a) in the current route, in which case the signals behind it are set (and behind any other trains in the current
16575  route), but only within the current route; or (b) in a linked rear route, in which case the function sets no further signals.
16576 */
16577 {
16578  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetTrailingSignalsOnContinuationRoute," + AnsiString(RouteNumber) + "," +
16579  AnsiString(AccessNumber));
16580  TPrefDirElement RouteElement;
16581  int Attribute = AccessNumber + 1;
16582 // signal attributes: 0=red; 1=yellow; 2=double yellow; 3 = green
16583  int x = GetFixedRouteAt(121, RouteNumber).PrefDirSize() - 1;
16584 
16585  if(!(GetFixedRouteAt(122, RouteNumber).GetFixedPrefDirElementAt(140, x).AutoSignals))
16586  {
16587  throw Exception("Error - route not AutoSignals in SetTrailingSignalsOnContinuationRoute");
16588  }
16589  if(GetFixedRouteAt(123, RouteNumber).GetFixedPrefDirElementAt(141, x).TrackType != Continuation)
16590  {
16591  throw Exception("Error - end element not continuation in SetTrailingSignalsOnContinuationRoute");
16592  }
16593  if(GetFixedRouteAt(124, RouteNumber).GetFixedPrefDirElementAt(142, x).Config[GetFixedRouteAt(125, RouteNumber).GetFixedPrefDirElementAt(143,
16594  x).XLinkPos] != End)
16595  {
16596  throw Exception("Error - end element a continuation in SetTrailingSignalsOnContinuationRoute but End not facing right way");
16597  }
16598 // new function
16599  SetAllRearwardsSignals(6, Attribute, RouteNumber, GetFixedRouteAt(126, RouteNumber).PrefDirSize() - 1);
16600  Utilities->CallLogPop(410);
16601 }
16602 
16603 // ---------------------------------------------------------------------------
16604 
16605 void TAllRoutes::SetAllRearwardsSignals(int Caller, int Attribute, int RouteNumber, int RouteStartPosition)
16606 /*
16607  Sets signals in all linked rearwards routes from the RouteStartPosition in RouteNumber, unless find a train (a) in the current route,
16608  in which case the signals behind it are set (and behind any other trains in the current route), but only within the current route;
16609  or (b) in a linked rear route, in which case the function sets no further signals.
16610 
16611  First call SetRearwardsSignalsReturnFalseForTrain (which is only called by this function) to set signals in route RouteNumber according
16612  to the received or modified (because of the forward look for buffers or continuation) Attribute. If no train is found during this call
16613  (returns true) then check for and call SetRearwardsSignalsReturnFalseForTrain for each rearwards linked route until either reach the
16614  beginning of the last linked route or find a train on a linked rear route. If no train was found during the RouteNumber call to
16615  SetRearwardsSignalsReturnFalseForTrain then the function terminates here.
16616  However if a train was found during the RouteNumber call to SetRearwardsSignalsReturnFalseForTrain then need to continue after the
16617  train in case had just added a route segment behind a train that now forms part of a single continuous route, otherwise the signals
16618  won't be set behind the train. First the route is examined element by element from the RouteStartPosition towards the start of the
16619  route until the train is found. Then the route elements are examined from the TrainPosition towards the start of the route until the
16620  first element behind the train is found. A recursive call to this function is then made from this behind-train position, to set all
16621  signals behind the train (and behind as many trains as there are on the single route) beginning with a red signal for the first signal
16622  found behind the train.
16623 
16624  Description of SetRearwardsSignalsReturnFalseForTrain for reference:
16625  Enter with Attribute set to the value to be used (unless modified by the initial forward search - see later) for the first rearwards
16626  signal found, and with PrefDirVectorStartPosition set to the position in PrefDirVector to begin the search. BUT, don't begin with the
16627  rearward search, first search forwards from the PrefDirVectorStartPosition in case the end of the route is a buffer or continuation, and
16628  modify the Attribute accordingly UNLESS (a) train present between PrefDirVectorStartPosition & end; (b) route in
16629  ContinuationAutoSigVector (i.e. train has exited the route at a continuation but it is still affecting the signals), or (c) truncating
16630  a route.
16631 
16632  Having received or modified Attribute as above, work backwards from the PrefDirVectorStartPosition until find a train - return false, or a
16633  signal. If find a signal set its Attribute to the current Attribute value up to a maximum of 3, and replot the signal as well as
16634  the required route and direction (if required) graphics, then increment Attribute up to a max. of 3 and continue working backwards
16635  for the next signal (or train - return false as before) and so on. On completion Attribute is passed back from the function as a
16636  reference. If no train is found before the beginning of the route is reached the function returns true.
16637 
16638 */
16639 {
16640  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetAllRearwardsSignals," + AnsiString(Attribute) + "," +
16641  AnsiString(RouteNumber) + "," + AnsiString(RouteStartPosition));
16642  TPrefDirElement FirstElement = GetFixedRouteAt(127, RouteNumber).GetFixedPrefDirElementAt(144, 0);
16643  int RearwardLinkedRouteNumber;
16644 
16645  Track->LCFoundInRouteBuildingFlag = false; // only examined for the new route segment, not for linked routes
16646  if(GetFixedRouteAt(128, RouteNumber).SetRearwardsSignalsReturnFalseForTrain(1, Attribute, RouteStartPosition)) // updates Attribute to 1+ final
16647  // signal value in the route for use in further linked routes
16648  {
16649  if(FirstElement.Conn[FirstElement.ELinkPos] > -1) // GetRouteTypeAndNumber tests for this but check here to avoid call if == -1
16650  {
16651  while(GetRouteTypeAndNumber(6, FirstElement.Conn[FirstElement.ELinkPos], FirstElement.ConnLinkPos[FirstElement.ELinkPos],
16652  RearwardLinkedRouteNumber) != TAllRoutes::NoRoute)
16653  {
16654  if(!(GetFixedRouteAt(129, RearwardLinkedRouteNumber).SetRearwardsSignalsReturnFalseForTrain(2, Attribute, AllRoutes->GetFixedRouteAt(130,
16655  RearwardLinkedRouteNumber).PrefDirSize() - 1)))
16656  break;
16657  // in above the RouteSettingFlag is set to false because this call is for routes that lie behind the route that is being set so don't want to
16658  // flash LCs on those routes
16659  FirstElement = AllRoutes->GetFixedRouteAt(131, RearwardLinkedRouteNumber).GetFixedPrefDirElementAt(145, 0);
16660  }
16661  }
16662  }
16663  else
16664  // found a train in the entry route before the beginning of the route, so need to continue after the train in case had just added a
16665  // route segment behind a train that now forms part of a single continuous route, otherwise the signals won't be set behind the train
16666  {
16667  int TrainID, TrainPosition, BehindTrainPosition;
16668  bool FoundTrain = false, BehindTrain = false;
16669  for(int x = RouteStartPosition; x >= 0; x--) // first step back from start position until find the train....
16670  {
16671  TPrefDirElement PrefDirElement = GetFixedRouteAt(132, RouteNumber).GetFixedPrefDirElementAt(146, x);
16672  TTrackElement TrackElement = Track->TrackElementAt(160, PrefDirElement.TrackVectorPosition);
16673  TrainID = TrackElement.TrainIDOnElement;
16674  if(TrackElement.TrackType == Bridge)
16675  {
16676  if(PrefDirElement.XLinkPos < 2)
16677  TrainID = TrackElement.TrainIDOnBridgeTrackPos01;
16678  else
16679  TrainID = TrackElement.TrainIDOnBridgeTrackPos23;
16680  }
16681  if(TrainID == -1)
16682  continue;
16683  else
16684  {
16685  FoundTrain = true;
16686  TrainPosition = x;
16687  break;
16688  }
16689  }
16690  if(FoundTrain && (TrainPosition > 1)) // if TrainPosition 1 or less then no route behind the train so can stop
16691  {
16692  for(int x = TrainPosition; x >= 0; x--) // then step back from that position until find element behind the train - ignore any
16693  // signals that the train itself is straddling, need the first signal behind the train to be set to red, when the train passes
16694  // the signal it's straddling the rearwards signals will be reset again. Even if there are two or more trains adjacent still
16695  // need the element behind the rearmost train.
16696  {
16697  TPrefDirElement PrefDirElement = GetFixedRouteAt(133, RouteNumber).GetFixedPrefDirElementAt(147, x);
16698  TTrackElement TrackElement = Track->TrackElementAt(161, PrefDirElement.TrackVectorPosition);
16699  TrainID = TrackElement.TrainIDOnElement;
16700  if(TrackElement.TrackType == Bridge)
16701  {
16702  if(PrefDirElement.XLinkPos < 2)
16703  TrainID = TrackElement.TrainIDOnBridgeTrackPos01;
16704  else
16705  TrainID = TrackElement.TrainIDOnBridgeTrackPos23;
16706  }
16707  if(TrainID != -1)
16708  continue; // still on train
16709  else
16710  {
16711  BehindTrain = true;
16712  BehindTrainPosition = x;
16713  break;
16714  }
16715  }
16716  if(BehindTrain) // then carry out a recursive rearward signal setting behind the train &
16717  // so on for as many trains as there are on the single route
16718  {
16719  SetAllRearwardsSignals(7, 0, RouteNumber, BehindTrainPosition); // false because can't set a route where there is a train
16720  // first signal behind train to be red
16721  }
16722  }
16723  }
16724  Utilities->CallLogPop(411);
16725 }
16726 
16727 // ---------------------------------------------------------------------------
16728 
16729 bool TAllRoutes::RouteLockingRequired(int Caller, int RouteNumber, int RouteTruncatePosition)
16730 {
16731 /* Locked if a train moving in the direction of the route within 3 signals back from truncate point (on the route itself or any linked routes, or on the element
16732  immediately before the start of the route or linked route - this because train cancels route elements that it touches) unless
16733  first signal is red, then OK
16734 */
16735  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RouteLockingRequired," + AnsiString(RouteNumber) + "," +
16736  AnsiString(RouteTruncatePosition));
16737  int SignalCount = 0, TrainID, RearwardLinkedRouteNumber, StartPosition = RouteTruncatePosition;
16738  TOneRoute CurrentRoute = GetFixedRouteAt(134, RouteNumber);
16739  TPrefDirElement PrefDirElement, FirstElement;
16740  TTrackElement TrackElement;
16741  bool ExamineRoute = true;
16742 
16743  while(ExamineRoute)
16744  {
16745  for(int x = StartPosition; x >= 0; x--) //work back along the route from the truncate point
16746  {
16747  PrefDirElement = CurrentRoute.GetFixedPrefDirElementAt(148, x);
16748  TrackElement = Track->TrackElementAt(162, PrefDirElement.TrackVectorPosition);
16749  TrainID = TrackElement.TrainIDOnElement;
16750  if(TrackElement.TrackType == Bridge)
16751  {
16752  if(PrefDirElement.XLinkPos < 2)
16753  TrainID = TrackElement.TrainIDOnBridgeTrackPos01;
16754  else
16755  TrainID = TrackElement.TrainIDOnBridgeTrackPos23;
16756  }
16757  if(TrainID > -1)
16758  {
16759  if(TrainController->TrainVectorAtIdent(36, TrainID).Stopped())
16760  { //any trains further back in route will be protected by the red signal behind the stopped train
16761  Utilities->CallLogPop(412);
16762  return false;
16763  }
16764  //added after v2.4.1 for trains facing the wrong way & moving but haven't moved a half element yet so route still intact
16765  if(TrainController->TrainVectorAtIdent(49, TrainID).GetLeadElement() != PrefDirElement.TrackVectorPosition) //if it isn't then the train is facing the
16766  //other way & can cancel the route
16767  {
16768  Utilities->CallLogPop(2203);
16769  return false;
16770  }
16771  Utilities->CallLogPop(1961); //otherwise need to lock the route as have found a train on the route (trains forward of the truncate point caught by
16772  return true; //TrainOccupyingRoute which is outside this function but also causes route locking)
16773  }
16774  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal) // XLinkPos because signal has to be facing same direction as PrefDir to count
16775  {
16776  if(TrackElement.Attribute == 0)
16777  {
16778  Utilities->CallLogPop(413);
16779  return false; // OK, red signal in front of a train
16780  }
16781  SignalCount++;
16782  if(SignalCount >= 3)
16783  {
16784  Utilities->CallLogPop(414);
16785  return false;
16786  }
16787  }
16788  if(PrefDirElement.Config[PrefDirElement.ELinkPos] == End) // buffer or continuation & no train
16789  // ElinkPos because working back along PrefDir to beginning
16790  {
16791  Utilities->CallLogPop(415);
16792  return false; // test - set to true to create a locked buffer-ended route, false for normal use
16793  }
16794  }
16795  //now look at linked rearwards routes
16796  FirstElement = CurrentRoute.GetFixedPrefDirElementAt(149, 0);
16797  StartPosition = CurrentRoute.PrefDirSize() - 1;
16798  if(GetRouteTypeAndNumber(7, FirstElement.Conn[FirstElement.ELinkPos], FirstElement.ConnLinkPos[FirstElement.ELinkPos],
16799  RearwardLinkedRouteNumber) != TAllRoutes::NoRoute)
16800  {
16801  CurrentRoute = GetFixedRouteAt(135, RearwardLinkedRouteNumber);
16802  ExamineRoute = true;
16803  StartPosition = GetFixedRouteAt(136, RearwardLinkedRouteNumber).PrefDirSize() - 1;
16804  }
16805  else
16806  {
16807  // here check for a train on the element immediately before the first route element
16808  TTrackElement PriorTrackElement = Track->TrackElementAt(489, FirstElement.Conn[FirstElement.ELinkPos]);
16809  TrainID = PriorTrackElement.TrainIDOnElement;
16810  if(PriorTrackElement.TrackType == Bridge)
16811  {
16812  if(FirstElement.ConnLinkPos[FirstElement.ELinkPos] < 2)
16813  TrainID = PriorTrackElement.TrainIDOnBridgeTrackPos01;
16814  else
16815  TrainID = PriorTrackElement.TrainIDOnBridgeTrackPos23;
16816  }
16817  if(TrainID > -1)
16818  {
16819  if(TrainController->TrainVectorAtIdent(37, TrainID).Stopped())
16820  {
16821  Utilities->CallLogPop(748);
16822  return false;
16823  }
16824  //added after v2.4.1 for trains facing the wrong way on the prior element & moving but haven't moved a half element yet
16825  if(TrainController->TrainVectorAtIdent(50, TrainID).GetLeadElement() != FirstElement.Conn[FirstElement.ELinkPos]) //if it isn't then the train is facing the
16826  //other way & can cancel the route
16827  {
16828  Utilities->CallLogPop(2204);
16829  return false;
16830  }
16831  Utilities->CallLogPop(1962);
16832  return true; //otherwise need to lock the route
16833  }
16834  ExamineRoute = false;
16835  }
16836  }
16837 // if reach beginning of all rear routes without finding a train and there aren't 3 signals then truncate the route
16838 // as trains running on unrouted lines are already at risk of wrong points etc so no benefit locking the route
16839  Utilities->CallLogPop(416);
16840  return false;
16841 }
16842 
16843 // ---------------------------------------------------------------------------
16844 
16845 bool TAllRoutes::IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(int Caller, int TrackVectorPosition, int XLinkPos,
16846  TPrefDirElement &PrefDirElement, int &LockedVectorNumber)
16847 {
16848  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber," +
16849  AnsiString(TrackVectorPosition) + "," + AnsiString(XLinkPos));
16850  TPrefDirElement InternalPrefDirElement; // blank element
16851 
16852  PrefDirElement = InternalPrefDirElement;
16853  if(LockedRouteVector.empty())
16854  {
16855  Utilities->CallLogPop(417);
16856  return false;
16857  }
16858 // make sure at least one locked route record is still valid - train may have removed it, if last element still present locked route still exists,
16859 // even if some elements have been removed from the front by a train
16860  bool InLockedRoute = false;
16861 
16862  for(TLockedRouteVectorIterator LRVIT = LockedRouteVector.begin(); LRVIT < LockedRouteVector.end(); LRVIT++)
16863  {
16864  if(TrackIsInARoute(14, LRVIT->LastTrackVectorPosition, LRVIT->LastXLinkPos))
16865  { // end of route can't be points, crossover or bridge so danger of route being on the other track of a 2-track element
16866  // doesn't arise)
16867  InLockedRoute = true;
16868  break;
16869  }
16870  }
16871  if(!InLockedRoute)
16872  {
16873  Utilities->CallLogPop(418);
16874  return false;
16875  }
16876 
16877  int RouteNumber, VectorCount = 0;
16878  TRouteType RouteType;
16879 
16880  for(TLockedRouteVectorIterator LRVIT = LockedRouteVector.begin(); LRVIT < LockedRouteVector.end(); LRVIT++)
16881  {
16882  RouteType = GetRouteTypeAndNumber(8, LRVIT->LastTrackVectorPosition, LRVIT->LastXLinkPos, RouteNumber);
16883  if(RouteType == NoRoute)
16884  continue;
16885  if((GetFixedRouteAt(137, RouteNumber).GetFixedPrefDirElementAt(150, GetFixedRouteAt(138, RouteNumber).PrefDirSize() - 1).TrackVectorPosition != (int)
16886  LRVIT->LastTrackVectorPosition) || (GetFixedRouteAt(139, RouteNumber).GetFixedPrefDirElementAt(151,
16887  GetFixedRouteAt(140, RouteNumber).PrefDirSize() - 1).XLinkPos != LRVIT->LastXLinkPos))
16888  {
16889  throw Exception
16890  ("Error, last element in locked route doesn't correspond with last element in associated route in IsElementInLockedRouteGetPrefDirElement");
16891  }
16892  for(int x = GetFixedRouteAt(141, RouteNumber).PrefDirSize() - 1; x >= 0; x--)
16893  {
16894  InternalPrefDirElement = GetFixedRouteAt(142, RouteNumber).GetFixedPrefDirElementAt(152, x);
16895  if(InternalPrefDirElement.TrackVectorPosition != (int)LRVIT->TruncateTrackVectorPosition)
16896  {
16897  if((InternalPrefDirElement.TrackVectorPosition == TrackVectorPosition) && (InternalPrefDirElement.XLinkPos == XLinkPos))
16898  {
16899  PrefDirElement = InternalPrefDirElement;
16900  LockedVectorNumber = VectorCount;
16901  Utilities->CallLogPop(419);
16902  return true;
16903  }
16904  }
16905  else if(InternalPrefDirElement.TrackVectorPosition == (int)LRVIT->TruncateTrackVectorPosition)
16906  {
16907  if((InternalPrefDirElement.TrackVectorPosition == TrackVectorPosition) && (InternalPrefDirElement.XLinkPos == XLinkPos))
16908  {
16909  PrefDirElement = InternalPrefDirElement;
16910  LockedVectorNumber = VectorCount;
16911  Utilities->CallLogPop(420);
16912  return true;
16913  }
16914  else
16915  break; // reached & tested LRVIT->TruncateTrackVectorPosition for a match so don't want to go any further for this route
16916  }
16917  }
16918  VectorCount++;
16919  }
16920  Utilities->CallLogPop(421);
16921  return false;
16922 }
16923 
16924 // ---------------------------------------------------------------------------
16925 
16927 {
16928  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteVectorNumber," + AnsiString(RouteID.GetInt()));
16929  for(unsigned int x = 0; x < AllRoutesSize(); x++)
16930  {
16931  if(GetFixedRouteAt(157, x).RouteID == RouteID.GetInt())
16932  {
16933  Utilities->CallLogPop(963);
16934  return x;
16935  }
16936  }
16937  throw Exception("Error, failed to find RouteID in GetRouteVectorNumber for ID: " + AnsiString(RouteID.GetInt()));
16938 }
16939 
16940 // ---------------------------------------------------------------------------
16941 
16943  // added at v1.3.1 after an error was generated when operating Ian Walker's Chiltern Railway
16944  // found to be due to a route having been removed by a train moving in the wrong direction after the route was selected but before it completed (i.e. route removed while flashing)
16945 {
16946  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsThereARouteAtIDNumber," + AnsiString(RouteID.GetInt()));
16947  for(unsigned int x = 0; x < AllRoutesSize(); x++)
16948  {
16949  if(GetFixedRouteAt(45, x).RouteID == RouteID.GetInt())
16950  {
16951  Utilities->CallLogPop(2039);
16952  return true;
16953  }
16954  }
16955  Utilities->CallLogPop(2040);
16956  return false;
16957 }
16958 
16959 // ---------------------------------------------------------------------------
16960 
16962 {
16963  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFixedRouteAtIDNumber," + AnsiString(RouteID.GetInt()));
16964  for(unsigned int x = 0; x < AllRoutesSize(); x++)
16965  {
16966  if(GetFixedRouteAt(163, x).RouteID == RouteID.GetInt())
16967  {
16968  Utilities->CallLogPop(964);
16969  return GetFixedRouteAt(159, x);
16970  }
16971  }
16972  throw Exception("Error, failed to find RouteID in GetFixedRouteAtIDNumber for ID: " + AnsiString(RouteID.GetInt()));
16973 }
16974 
16975 // ---------------------------------------------------------------------------
16976 
16978 {
16979  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetModifiableRouteATIDNumber," + AnsiString(RouteID.GetInt()));
16980  for(unsigned int x = 0; x < AllRoutesSize(); x++)
16981  {
16982  if(GetFixedRouteAt(164, x).RouteID == RouteID.GetInt())
16983  {
16984  Utilities->CallLogPop(965);
16985  return GetModifiableRouteAt(15, x);
16986  }
16987  }
16988  throw Exception("Error, failed to find RouteID in GetModifiableRouteAtIDNumber for ID: " + AnsiString(RouteID.GetInt()));
16989 }
16990 
16991 // ---------------------------------------------------------------------------
16992 
16993 void TAllRoutes::SaveRoutes(int Caller, std::ofstream &OutFile)
16994 {
16995  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveRoutes");
16996  Utilities->SaveFileInt(OutFile, AllRoutesSize()); // so know how many to reload
16997  Utilities->SaveFileInt(OutFile, NextRouteID);
16998  for(unsigned int x = 0; x < AllRoutesSize(); x++)
16999  {
17000  TOneRoute OneRoute = GetFixedRouteAt(165, x);
17001  Utilities->SaveFileInt(OutFile, OneRoute.RouteID);
17002  OneRoute.SavePrefDirVector(6, OutFile);
17003  }
17004  Utilities->CallLogPop(1442);
17005 }
17006 
17007 // ---------------------------------------------------------------------------
17008 
17009 bool TAllRoutes::LoadRoutes(int Caller, std::ifstream &InFile)
17010 {
17011  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadRoutes");
17012  int NumberOfRoutes;
17013 
17014  NumberOfRoutes = Utilities->LoadFileInt(InFile);
17015  NextRouteID = Utilities->LoadFileInt(InFile);
17016  for(int x = 0; x < NumberOfRoutes; x++)
17017  {
17018  TOneRoute OneRoute; // empty route
17019  OneRoute.RouteID = Utilities->LoadFileInt(InFile);
17020  OneRoute.LoadPrefDir(2, InFile);
17022  {
17023  StoreOneRouteAfterSessionLoad(0, &OneRoute);
17024  }
17025  else
17026  {
17027  Utilities->CallLogPop(1443);
17028  return false;
17029  }
17030  }
17031  Utilities->CallLogPop(1444);
17032  return true;
17033 }
17034 
17035 // ---------------------------------------------------------------------------
17036 bool TAllRoutes::CheckRoutes(int Caller, int NumberOfActiveElements, std::ifstream &InFile)
17037 {
17038  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckRoutes," + AnsiString(NumberOfActiveElements));
17039  int NumberOfRoutes = Utilities->LoadFileInt(InFile);
17040 
17041  if((NumberOfRoutes < 0) || (NumberOfRoutes > 5000))
17042  {
17043  Utilities->CallLogPop(1445);
17044  return false;
17045  }
17046  int NextID = Utilities->LoadFileInt(InFile);
17047 
17048  if((NextID < 0) || (NextID > 1000000))
17049  {
17050  Utilities->CallLogPop(1446);
17051  return false;
17052  }
17053  for(int x = 0; x < NumberOfRoutes; x++)
17054  {
17055  int RouteID = Utilities->LoadFileInt(InFile);
17056  if((RouteID < 0) || (RouteID > 20000))
17057  {
17058  Utilities->CallLogPop(1447);
17059  return false;
17060  }
17061  TOneRoute OneRoute; // create an empty route so CheckOnePrefDir can be called
17062  if(!(OneRoute.CheckOnePrefDir(3, NumberOfActiveElements, InFile)))
17063  {
17064  Utilities->CallLogPop(1448);
17065  return false;
17066  }
17067  }
17068  Utilities->CallLogPop(1449);
17069  return true;
17070 }
17071 
17072 // ---------------------------------------------------------------------------
17073 
17074 bool TAllRoutes::CheckForLoopingRoute(int Caller, int EndPosition, int EndXLinkPos, int StartPosition)
17075 { // return true for a loop
17076  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckForLoopingRoute," + AnsiString(EndPosition) + "," +
17077  AnsiString(StartPosition));
17078  if(EndPosition == StartPosition)
17079  {
17080  Utilities->CallLogPop(1839);
17081  return true; // shouldn't happen but treat as a loop if does
17082  }
17083 // begin at EndPosition & EndXLinkPos & work forwards until reach end of route (return false) or StartElement (return true)
17084  int TVPos = EndPosition;
17085  int LkPos = EndXLinkPos;
17086 
17087  while(TrackIsInARoute(15, TVPos, LkPos))
17088  {
17089  int NewTVPos = Track->TrackElementAt(826, TVPos).Conn[LkPos];
17090  int NewLkPos = -1;
17091  if(NewTVPos > -1)
17092  {
17093  NewLkPos = Track->TrackElementAt(827, TVPos).ConnLinkPos[LkPos]; // this is the entry link pos
17094  if(NewLkPos == -1)
17095  {
17096  Utilities->CallLogPop(1840);
17097  return true; // shouldn't arise but treat as loop if does
17098  }
17099  }
17100  else // reached a buffer or continuation
17101  {
17102  Utilities->CallLogPop(1841);
17103  return false;
17104  }
17105  TVPos = NewTVPos;
17106  if(Track->TrackElementAt(828, TVPos).TrackType == Points)
17107  {
17108  if((NewLkPos == 0) || (NewLkPos == 2)) // leading points
17109  {
17110  if(Track->TrackElementAt(829, TVPos).Attribute == 0)
17111  LkPos = 1;
17112  else
17113  LkPos = 3;
17114  }
17115  else
17116  LkPos = 0;
17117  }
17118  else
17119  LkPos = Track->GetNonPointsOppositeLinkPos(NewLkPos);
17120  if(TVPos == StartPosition)
17121  {
17122  Utilities->CallLogPop(1842);
17123  return true; // it is a loop
17124  }
17125  }
17126  Utilities->CallLogPop(1843);
17127  return false; // reached end of route so not a loop
17128 }
17129 
17130 // ---------------------------------------------------------------------------
17131 
17132 bool TAllRoutes::DiagonalFouledByRouteOrTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber)
17133 /*
17134  Track geometry allows diagonals to cross without occupying the same track element, so when
17135  route plotting it is necessary to check if there is an existing route or a train on such a crossing
17136  diagonal. Returns true for a fouled diagonal. Enter with H & V set for the element whose diagonal
17137  is to be checked, and the XLink number of the relevant diagonal, which must be 1, 3, 7 or 9.
17138  for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
17139  for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
17140  for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
17141  for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
17142  Each of these is examined in turn for each route element in the relevant position.
17143 
17144  NOTE: Originally this failed to detect a train fouling a diagonal. v1.2.0 checks for a train present on a
17145  crossing diagonal element using a new bool function TTrack::TrainOnLink(int HLoc, int VLoc, int Link)
17146  that returns false in all cases (including elements & links not present) except train present.
17147 */
17148 {
17149  int TrainID; // not used in this function
17150 
17151  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DiagonalFouledByRouteOrTrain," + AnsiString(HLoc) + "," +
17152  AnsiString(VLoc) + "," + AnsiString(DiagonalLinkNumber));
17153  TPrefDirElement TempPrefDirElement;
17154  TAllRoutes::TRouteElementPair FirstPair, SecondPair;
17155 
17156  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(4, HLoc - 1, VLoc, SecondPair);
17157  if(FirstPair.first > -1)
17158  {
17159  TempPrefDirElement = AllRoutes->GetFixedRouteAt(50, FirstPair.first).GetFixedPrefDirElementAt(70, FirstPair.second);
17160  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
17161  {
17162  Utilities->CallLogPop(310);
17163  return true;
17164  }
17165  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
17166  {
17167  Utilities->CallLogPop(311);
17168  return true;
17169  }
17170  }
17171  if(SecondPair.first > -1)
17172  {
17173  TempPrefDirElement = AllRoutes->GetFixedRouteAt(51, SecondPair.first).GetFixedPrefDirElementAt(71, SecondPair.second);
17174  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
17175  {
17176  Utilities->CallLogPop(312);
17177  return true;
17178  }
17179  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
17180  {
17181  Utilities->CallLogPop(313);
17182  return true;
17183  }
17184  }
17185 
17186  if(((DiagonalLinkNumber == 1) && Track->TrainOnLink(0, HLoc - 1, VLoc, 3, TrainID)) || ((DiagonalLinkNumber == 7) && Track->TrainOnLink(1, HLoc - 1, VLoc,
17187  9, TrainID)))
17188  {
17189  Utilities->CallLogPop(1997);
17190  return true;
17191  }
17192 
17193  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(5, HLoc, VLoc - 1, SecondPair);
17194  if(FirstPair.first > -1)
17195  {
17196  TempPrefDirElement = AllRoutes->GetFixedRouteAt(52, FirstPair.first).GetFixedPrefDirElementAt(72, FirstPair.second);
17197  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
17198  {
17199  Utilities->CallLogPop(314);
17200  return true;
17201  }
17202  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
17203  {
17204  Utilities->CallLogPop(315);
17205  return true;
17206  }
17207  }
17208  if(SecondPair.first > -1)
17209  {
17210  TempPrefDirElement = AllRoutes->GetFixedRouteAt(53, SecondPair.first).GetFixedPrefDirElementAt(73, SecondPair.second);
17211  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
17212  {
17213  Utilities->CallLogPop(316);
17214  return true;
17215  }
17216  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
17217  {
17218  Utilities->CallLogPop(317);
17219  return true;
17220  }
17221  }
17222 
17223  if(((DiagonalLinkNumber == 1) && Track->TrainOnLink(2, HLoc, VLoc - 1, 7, TrainID)) || ((DiagonalLinkNumber == 3) && Track->TrainOnLink(3, HLoc, VLoc - 1,
17224  9, TrainID)))
17225  {
17226  Utilities->CallLogPop(1998);
17227  return true;
17228  }
17229 
17230  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(6, HLoc + 1, VLoc, SecondPair);
17231  if(FirstPair.first > -1)
17232  {
17233  TempPrefDirElement = AllRoutes->GetFixedRouteAt(54, FirstPair.first).GetFixedPrefDirElementAt(74, FirstPair.second);
17234  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
17235  {
17236  Utilities->CallLogPop(318);
17237  return true;
17238  }
17239  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
17240  {
17241  Utilities->CallLogPop(319);
17242  return true;
17243  }
17244  }
17245  if(SecondPair.first > -1)
17246  {
17247  TempPrefDirElement = AllRoutes->GetFixedRouteAt(55, SecondPair.first).GetFixedPrefDirElementAt(75, SecondPair.second);
17248  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
17249  {
17250  Utilities->CallLogPop(320);
17251  return true;
17252  }
17253  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
17254  {
17255  Utilities->CallLogPop(321);
17256  return true;
17257  }
17258  }
17259 
17260  if(((DiagonalLinkNumber == 3) && Track->TrainOnLink(4, HLoc + 1, VLoc, 1, TrainID)) || ((DiagonalLinkNumber == 9) && Track->TrainOnLink(5, HLoc + 1, VLoc,
17261  7, TrainID)))
17262  {
17263  Utilities->CallLogPop(1999);
17264  return true;
17265  }
17266 
17267  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(7, HLoc, VLoc + 1, SecondPair);
17268  if(FirstPair.first > -1)
17269  {
17270  TempPrefDirElement = AllRoutes->GetFixedRouteAt(56, FirstPair.first).GetFixedPrefDirElementAt(76, FirstPair.second);
17271  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
17272  {
17273  Utilities->CallLogPop(322);
17274  return true;
17275  }
17276  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
17277  {
17278  Utilities->CallLogPop(323);
17279  return true;
17280  }
17281  }
17282  if(SecondPair.first > -1)
17283  {
17284  TempPrefDirElement = AllRoutes->GetFixedRouteAt(57, SecondPair.first).GetFixedPrefDirElementAt(77, SecondPair.second);
17285  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
17286  {
17287  Utilities->CallLogPop(324);
17288  return true;
17289  }
17290  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
17291  {
17292  Utilities->CallLogPop(325);
17293  return true;
17294  }
17295  }
17296 
17297  if(((DiagonalLinkNumber == 7) && Track->TrainOnLink(6, HLoc, VLoc + 1, 1, TrainID)) || ((DiagonalLinkNumber == 9) && Track->TrainOnLink(7, HLoc, VLoc + 1,
17298  3, TrainID)))
17299  {
17300  Utilities->CallLogPop(2000);
17301  return true;
17302  }
17303 
17304  Utilities->CallLogPop(326);
17305  return false;
17306 }
17307 
17308 // ---------------------------------------------------------------------------
17309 
17310 bool TAllRoutes::DiagonalFouledByRoute(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber)
17311 /*
17312  As above but checks for a route only (may or may not be a train). Enter with H & V set for the element whose diagonal
17313  is to be checked, and the XLink number of the relevant diagonal, which must be 1, 3, 7 or 9.
17314  for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
17315  for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
17316  for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
17317  for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
17318  Each of these is examined in turn for each route element in the relevant position.
17319 */
17320 {
17321  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DiagonalFouledByRoute," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
17322  "," + AnsiString(DiagonalLinkNumber));
17323  TPrefDirElement TempPrefDirElement;
17324  TAllRoutes::TRouteElementPair FirstPair, SecondPair;
17325 
17326  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(17, HLoc - 1, VLoc, SecondPair);
17327  if(FirstPair.first > -1)
17328  {
17329  TempPrefDirElement = AllRoutes->GetFixedRouteAt(197, FirstPair.first).GetFixedPrefDirElementAt(233, FirstPair.second);
17330  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
17331  {
17332  Utilities->CallLogPop(2010);
17333  return true;
17334  }
17335  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
17336  {
17337  Utilities->CallLogPop(2011);
17338  return true;
17339  }
17340  }
17341  if(SecondPair.first > -1)
17342  {
17343  TempPrefDirElement = AllRoutes->GetFixedRouteAt(198, SecondPair.first).GetFixedPrefDirElementAt(234, SecondPair.second);
17344  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
17345  {
17346  Utilities->CallLogPop(2012);
17347  return true;
17348  }
17349  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
17350  {
17351  Utilities->CallLogPop(2013);
17352  return true;
17353  }
17354  }
17355 
17356  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(18, HLoc, VLoc - 1, SecondPair);
17357  if(FirstPair.first > -1)
17358  {
17359  TempPrefDirElement = AllRoutes->GetFixedRouteAt(199, FirstPair.first).GetFixedPrefDirElementAt(235, FirstPair.second);
17360  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
17361  {
17362  Utilities->CallLogPop(2014);
17363  return true;
17364  }
17365  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
17366  {
17367  Utilities->CallLogPop(2015);
17368  return true;
17369  }
17370  }
17371  if(SecondPair.first > -1)
17372  {
17373  TempPrefDirElement = AllRoutes->GetFixedRouteAt(200, SecondPair.first).GetFixedPrefDirElementAt(236, SecondPair.second);
17374  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
17375  {
17376  Utilities->CallLogPop(2016);
17377  return true;
17378  }
17379  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
17380  {
17381  Utilities->CallLogPop(2017);
17382  return true;
17383  }
17384  }
17385 
17386  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(19, HLoc + 1, VLoc, SecondPair);
17387  if(FirstPair.first > -1)
17388  {
17389  TempPrefDirElement = AllRoutes->GetFixedRouteAt(201, FirstPair.first).GetFixedPrefDirElementAt(237, FirstPair.second);
17390  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
17391  {
17392  Utilities->CallLogPop(2018);
17393  return true;
17394  }
17395  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
17396  {
17397  Utilities->CallLogPop(2019);
17398  return true;
17399  }
17400  }
17401  if(SecondPair.first > -1)
17402  {
17403  TempPrefDirElement = AllRoutes->GetFixedRouteAt(202, SecondPair.first).GetFixedPrefDirElementAt(238, SecondPair.second);
17404  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
17405  {
17406  Utilities->CallLogPop(2020);
17407  return true;
17408  }
17409  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
17410  {
17411  Utilities->CallLogPop(2021);
17412  return true;
17413  }
17414  }
17415 
17416  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(20, HLoc, VLoc + 1, SecondPair);
17417  if(FirstPair.first > -1)
17418  {
17419  TempPrefDirElement = AllRoutes->GetFixedRouteAt(203, FirstPair.first).GetFixedPrefDirElementAt(239, FirstPair.second);
17420  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
17421  {
17422  Utilities->CallLogPop(2022);
17423  return true;
17424  }
17425  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
17426  {
17427  Utilities->CallLogPop(2023);
17428  return true;
17429  }
17430  }
17431  if(SecondPair.first > -1)
17432  {
17433  TempPrefDirElement = AllRoutes->GetFixedRouteAt(204, SecondPair.first).GetFixedPrefDirElementAt(240, SecondPair.second);
17434  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
17435  {
17436  Utilities->CallLogPop(2024);
17437  return true;
17438  }
17439  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
17440  {
17441  Utilities->CallLogPop(2025);
17442  return true;
17443  }
17444  }
17445 
17446  Utilities->CallLogPop(2026);
17447  return false;
17448 }
17449 
17450 // ---------------------------------------------------------------------------
TTrain::LinkOccupied
bool LinkOccupied(int Caller, int TrackVectorPosition, int LinkNumber)
Added at v1.2.0: true if any part of train on specific link, false otherwise, including no link prese...
Definition: TrainUnit.cpp:7498
TRailGraphics::gl70
Graphics::TBitmap * gl70
Definition: GraphicUnit.h:676
TRailGraphics::bm72CallingOn
Graphics::TBitmap * bm72CallingOn
Definition: GraphicUnit.h:476
TAllRoutes::TrackIsInARoute
bool TrackIsInARoute(int Caller, int TrackVectorPosition, int LinkPos)
Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit)...
Definition: TrackUnit.cpp:15596
TPrefDirRoute
TPrefDirRoute
< used in TOnePrefDir::PrefDirMarker to indicate whether the function is being called for a preferred...
Definition: TrackUnit.h:1169
TRailGraphics::sm120
Graphics::TBitmap * sm120
Definition: GraphicUnit.h:908
TRailGraphics::bm7
Graphics::TBitmap * bm7
Definition: GraphicUnit.h:463
TOnePrefDir::LastElementPtr
TPrefDirVectorIterator LastElementPtr(int Caller)
Return a pointer to the last element in the vector.
Definition: TrackUnit.cpp:9712
TRailGraphics::gl58
Graphics::TBitmap * gl58
Definition: GraphicUnit.h:662
TUserGraphicItem::UserGraphic
TPicture * UserGraphic
Definition: DisplayUnit.h:36
TRailGraphics::gl145
Graphics::TBitmap * gl145
Definition: GraphicUnit.h:612
TRailGraphics::gl102
Graphics::TBitmap * gl102
Definition: GraphicUnit.h:564
TTrack::UserGraphicVectorAt
TUserGraphicItem & UserGraphicVectorAt(int Caller, int At)
A range-checked version of UserGraphicVector.at(At)
Definition: TrackUnit.cpp:9683
TGraphicElement::HPos
int HPos
Definition: TrackUnit.h:350
TTrack::GapVLoc
int GapVLoc
record gap setting info
Definition: TrackUnit.h:484
TTextItem::VPos
int VPos
the vertical position on the railway
Definition: TextUnit.h:50
TDisplay::DisplayOffsetHHome
static int DisplayOffsetHHome
the horizontal offset of the 'Home' display
Definition: DisplayUnit.h:80
TRailGraphics::bm11
Graphics::TBitmap * bm11
Definition: GraphicUnit.h:352
TRailGraphics::sm99
Graphics::TBitmap * sm99
Definition: GraphicUnit.h:867
TTrack::ResetGapsFromGapMap
bool ResetGapsFromGapMap(int Caller)
Called by RepositionAndMapTrack to reset the connecting elements of all set gaps (their TrackVector p...
Definition: TrackUnit.cpp:4921
TOnePrefDir::RebuildPrefDirVector
void RebuildPrefDirVector(int Caller)
Called after the track vector has been rebuilt following linking, to rebuild the preferred direction ...
Definition: TrackUnit.cpp:11167
TRailGraphics::sm129
Graphics::TBitmap * sm129
Definition: GraphicUnit.h:764
TFixedTrackPiece
Definition: TrackUnit.h:79
TFixedTrackPiece::PlotFixedTrackElement
void PlotFixedTrackElement(int Caller, int HLocInput, int VLocInput) const
Plot the element on the railway display at position HLocInput & VLocInput.
Definition: TrackUnit.cpp:106
TAllRoutes::LockedRouteVector
TLockedRouteVector LockedRouteVector
the vector that stores all the locked routes on the railway
Definition: TrackUnit.h:1570
TOneRoute::GetPreferredRouteStartElement
bool GetPreferredRouteStartElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool ConsecSignalsRoute, bool AutoSigsFlag)
Set the starting conditions for a preferred direction or automatic signal route selection beginning o...
Definition: TrackUnit.cpp:12256
TUtilities::LoadFileString
AnsiString LoadFileString(std::ifstream &InFile)
loads a string value from the file
Definition: Utilities.cpp:181
TTrack::LNDone2MultiMap
TLNDone2MultiMap LNDone2MultiMap
multimap of processed location name elements (see type for more information above)
Definition: TrackUnit.h:694
TTextHandler::RebuildFromTextVector
void RebuildFromTextVector(int Caller, TDisplay *Disp)
display all text items in TextVector on the screen
Definition: TextUnit.cpp:402
TRailGraphics::sm72
Graphics::TBitmap * sm72
Definition: GraphicUnit.h:899
TTrack::AnyLinkedLevelCrossingElementsWithRoutesOrTrains
bool AnyLinkedLevelCrossingElementsWithRoutesOrTrains(int Caller, int HLoc, int VLoc, bool &TrainPresent)
True if a route or train present on any linked level crossing element.
Definition: TrackUnit.cpp:6317
TAllRoutes::Route2MultiMapInsert
void Route2MultiMapInsert(int Caller, int HLoc, int VLoc, int ELinkIn, int RouteNumber, unsigned int RouteElementNumber)
Insert an entry in Route2MultiMap. Called by TAllRoutes::AddRouteElement.
Definition: TrackUnit.cpp:16199
TFixedTrackPiece::GraphicPtr
Graphics::TBitmap * GraphicPtr
the track bitmap for display on the zoomed-in railway
Definition: TrackUnit.h:89
TRailGraphics::sm2
Graphics::TBitmap * sm2
Definition: GraphicUnit.h:783
clB5G0R0
#define clB5G0R0
Definition: GraphicUnit.h:246
TRailGraphics::sm73
Graphics::TBitmap * sm73
Definition: GraphicUnit.h:900
TTrack::IsNamedNonStationLocationPresent
bool IsNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
True if a non-station named location at HLoc & VLoc.
Definition: TrackUnit.cpp:8442
TRailGraphics::sm21
Graphics::TBitmap * sm21
Definition: GraphicUnit.h:785
TAllRoutes::SetAllRearwardsSignals
void SetAllRearwardsSignals(int Caller, int Attribute, int RouteNumber, int RouteStartPosition)
Set rearwards signals from the specified route starting position.
Definition: TrackUnit.cpp:16605
TRailGraphics::sm123
Graphics::TBitmap * sm123
Definition: GraphicUnit.h:911
TOnePrefDir::SearchLimitLowV
int SearchLimitLowV
Definition: TrackUnit.h:1227
TRailGraphics::bm8
Graphics::TBitmap * bm8
Definition: GraphicUnit.h:508
TTrack::GapMap
TGapMap GapMap
map of gaps (see type for more information above)
Definition: TrackUnit.h:686
TRailGraphics::gl117
Graphics::TBitmap * gl117
Definition: GraphicUnit.h:580
TRailGraphics::gl89set
Graphics::TBitmap * gl89set
Definition: GraphicUnit.h:701
TOnePrefDir::ErasePrefDirElementAt
void ErasePrefDirElementAt(int Caller, int PrefDirVectorPosition)
Erase a single element from PrefDirVector and 4MultiMap, decrementing the remaining PrefDirElementNum...
Definition: TrackUnit.cpp:11426
TRailGraphics::sm104
Graphics::TBitmap * sm104
Definition: GraphicUnit.h:751
TRailGraphics::gl19
Graphics::TBitmap * gl19
Definition: GraphicUnit.h:619
TTrack::UserGraphicMap
TUserGraphicMap UserGraphicMap
the map of graphic filenames as key and TPicture* as values
Definition: TrackUnit.h:701
TGraphicElement::ScreenSourceSet
bool ScreenSourceSet
Definition: TrackUnit.h:348
TOnePrefDir::CheckPrefDirAgainstTrackVector
void CheckPrefDirAgainstTrackVector(int Caller)
Check loaded PrefDir against loaded track, and if discrepancies found give message & clear EveryPrefD...
Definition: TrackUnit.cpp:11207
TRailGraphics::gl72
Graphics::TBitmap * gl72
Definition: GraphicUnit.h:678
TRailGraphics::ChangeAllTransparentColours
void ChangeAllTransparentColours(TColor NewTransparentColour, TColor OldTransparentColour)
Definition: GraphicUnit.cpp:3543
TRailGraphics::gl88set
Graphics::TBitmap * gl88set
Definition: GraphicUnit.h:699
TRailGraphics::bm28
Graphics::TBitmap * bm28
Definition: GraphicUnit.h:394
TRailGraphics::bm68grounddblred
Graphics::TBitmap * bm68grounddblred
Definition: GraphicUnit.h:453
TOneRoute::GetNonPreferredRouteStartElement
bool GetNonPreferredRouteStartElement(int Caller, int HLoc, int VLoc, bool ConsecSignalsRoute, bool Callon)
Set the starting conditions for a non-preferred (i.e. unrestricted) route selection beginning on HLoc...
Definition: TrackUnit.cpp:13671
TTrack::BarriersDownVector
TActiveLCVector BarriersDownVector
vector of LCs with barriers down
Definition: TrackUnit.h:684
TPrefDirElement::GetXLinkPos
int GetXLinkPos() const
Returns the XLink array position.
Definition: TrackUnit.h:288
TTrack::IsLCBarrierDownAtHV
bool IsLCBarrierDownAtHV(int Caller, int HLoc, int VLoc)
True if an open (to trains) level crossing is found at H & V.
Definition: TrackUnit.cpp:6170
TAllRoutes::TLockedRouteClass::TruncateTrackVectorPosition
unsigned int TruncateTrackVectorPosition
the TrackVector position of the element selected for truncation
Definition: TrackUnit.h:1488
TRailGraphics::bm70grounddblred
Graphics::TBitmap * bm70grounddblred
Definition: GraphicUnit.h:466
TUtilities::ScreenElementWidth
int ScreenElementWidth
width of display screen in elements
Definition: Utilities.h:47
TRailGraphics::gl75
Graphics::TBitmap * gl75
Definition: GraphicUnit.h:683
TAllRoutes::LockedRouteLockStartTime
TDateTime LockedRouteLockStartTime
Definition: TrackUnit.h:1550
TTrack::TSigElement::Attribute
int Attribute
the signal state - red, yellow, double yellow or green
Definition: TrackUnit.h:623
TTrack::GetVectorPositionFromTrackMap
int GetVectorPositionFromTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
Returns the track vector position corresponding to the Hloc & VLoc positions, FoundFlag indicates whe...
Definition: TrackUnit.cpp:5057
TTrack::GetTrackElementFromTrackMap
TTrackElement & GetTrackElementFromTrackMap(int Caller, int HLoc, int VLoc)
Return a reference to the element at HLoc & VLoc, if no element is found an error is thrown.
Definition: TrackUnit.cpp:5084
TOneRoute::TRouteFlash::OverlayPlotted
bool OverlayPlotted
flag indicating the graphic that is currently displayed, true for the overlay (route-coloured)
Definition: TrackUnit.h:1373
TTrack::LeftPlatAllowed
Set< int, 1, 146 > LeftPlatAllowed
Definition: TrackUnit.h:504
TAllRoutes::TRouteElementPair
std::pair< int, unsigned int > TRouteElementPair
defines a specific element in a route, the first (int) value is the vector position in the AllRoutesV...
Definition: TrackUnit.h:1511
NamedNonStationLocation
@ NamedNonStationLocation
Definition: TrackUnit.h:65
TRailGraphics::sm51
Graphics::TBitmap * sm51
Definition: GraphicUnit.h:818
TRailGraphics::sm77
Graphics::TBitmap * sm77
Definition: GraphicUnit.h:839
TTrack::NoActiveTrack
bool NoActiveTrack(int Caller)
True if there is no active track in the railway.
Definition: TrackUnit.cpp:1644
TPrefDirElement::GetRouteAutoSigsGraphicPtr
Graphics::TBitmap * GetRouteAutoSigsGraphicPtr()
picks up the blue route graphic (not used - superseded by GetRouteGraphicPtr)
Definition: TrackUnit.cpp:740
TTrack::CalcHLocMinEtc
void CalcHLocMinEtc(int Caller)
Examine TrackVector, InactiveTrackVector and TextVector, and set the values that indicate the extent ...
Definition: TrackUnit.cpp:8754
TOneRoute::FindForwardTargetSignalAttribute
bool FindForwardTargetSignalAttribute(int Caller, int &NextForwardLinkedRouteNumber, int &Attribute) const
Used when setting signal aspects for a route by working forwards through the route to see what the ne...
Definition: TrackUnit.cpp:14908
TRailGraphics::gl143
Graphics::TBitmap * gl143
Definition: GraphicUnit.h:611
TRailGraphics::sm70
Graphics::TBitmap * sm70
Definition: GraphicUnit.h:897
TAllRoutes::DiagonalFouledByRoute
bool DiagonalFouledByRoute(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber)
As above but only checks for a route (may or may not be a train present (new at v1....
Definition: TrackUnit.cpp:17310
TGraphicElement::VPos
int VPos
horizontal and vertical positions
Definition: TrackUnit.h:350
TAllRoutes::LockedRouteFoundDuringRouteBuilding
bool LockedRouteFoundDuringRouteBuilding
this flags the fact that a locked route has been found during route building in an existing linked ro...
Definition: TrackUnit.h:1541
TTextHandler::TextVector
TTextVector TextVector
Definition: TextUnit.h:69
TTrack::Lowering
@ Lowering
Definition: TrackUnit.h:522
TTrack::FindNonPlatformMatch
bool FindNonPlatformMatch(int Caller, int HLoc, int VLoc, int &Position, TTrackElement &TrackElement)
True if find a non-platform element at HLoc & VLoc, and if so return its TrackVector position and a r...
Definition: TrackUnit.cpp:2448
TRailGraphics::bm73CallingOn
Graphics::TBitmap * bm73CallingOn
Definition: GraphicUnit.h:483
TTrack::TFixedTrackArray::FixedTrackPiece
TFixedTrackPiece FixedTrackPiece[FirstUnusedSpeedTagNumber]
the array member
Definition: TrackUnit.h:469
TTrack::MatchingPoint
bool MatchingPoint(int Caller, unsigned int TrackVectorPosition, unsigned int DivergingPosition)
Definition: TrackUnit.cpp:5213
TRailGraphics::gl66
Graphics::TBitmap * gl66
Definition: GraphicUnit.h:671
TRailGraphics::bm69grounddblred
Graphics::TBitmap * bm69grounddblred
Definition: GraphicUnit.h:459
TTrackElement::StationEntryStopLinkPos2
int StationEntryStopLinkPos2
Used for track at platforms and non-station named locations to mark the train front element stop posi...
Definition: TrackUnit.h:148
TTrack::EnterLocationName
void EnterLocationName(int Caller, AnsiString LocationName, bool AddingElements)
All platform, concourse, footcrossing & non-station named location elements are able to have a Locati...
Definition: TrackUnit.cpp:6960
TOneRoute::RouteSearchLimit
static const int RouteSearchLimit
limit to the number of elements searched in attempting to find a route
Definition: TrackUnit.h:1383
TUtilities::CheckFileStringZeroDelimiter
bool CheckFileStringZeroDelimiter(std::ifstream &InFile)
checks that the value is a string ('0' only accepted as the delimiter), returns true for success
Definition: Utilities.cpp:383
TTrack::TTrackVectorIterator
std::vector< TTrackElement >::iterator TTrackVectorIterator
iterator for TTrackVector
Definition: TrackUnit.h:560
TAllRoutes::ClearRouteDuringRouteBuildingAt
void ClearRouteDuringRouteBuildingAt(int Caller, int RouteNumber)
When attaching a new route section to an existing route, it is sometimes necessary to erase the origi...
Definition: TrackUnit.cpp:16032
TRailGraphics::sm108
Graphics::TBitmap * sm108
Definition: GraphicUnit.h:755
TTrack::Tag79Array
int Tag79Array[25][3]
Definition: TrackUnit.h:496
TRailGraphics::gl60
Graphics::TBitmap * gl60
Definition: GraphicUnit.h:665
TOnePrefDir::SavePrefDirVector
void SavePrefDirVector(int Caller, std::ofstream &VecFile)
Save the preferred direction vector to a file.
Definition: TrackUnit.cpp:10964
TRailGraphics::bm132
Graphics::TBitmap * bm132
Definition: GraphicUnit.h:359
TTrack::GetTrackLocsFromScreenPos
void GetTrackLocsFromScreenPos(int Caller, int &HLoc, int &VLoc, int ScreenPosH, int ScreenPosV)
Converse of GetScreenPositionsFromTruePos except that in this function HLoc & VLoc are expressed in t...
Definition: TrackUnit.cpp:6463
TRailGraphics::bm73
Graphics::TBitmap * bm73
Definition: GraphicUnit.h:482
TRailGraphics::bm30
Graphics::TBitmap * bm30
Definition: GraphicUnit.h:400
TTrainController::TrainVectorAtIdent
TTrain & TrainVectorAtIdent(int Caller, int TrainID)
Return a reference to the train with ID TrainID, carries out validity checking on TrainID.
Definition: TrainUnit.cpp:8481
TTrack::DecrementValuesInGapsAndTrackAndNameMaps
void DecrementValuesInGapsAndTrackAndNameMaps(int Caller, unsigned int VecPos)
After an element has been erased from the TrackVector, all the later elements are moved down one....
Definition: TrackUnit.cpp:7939
TOnePrefDir::GetStartAndEndPrefDirElements
bool GetStartAndEndPrefDirElements(int Caller, TPrefDirElement &StartElement, TPrefDirElement &EndElement, int &LastIteratorValue)
Called when searching for start and end PrefDirElements when setting up automatic signals routes in P...
Definition: TrackUnit.cpp:12057
TTextItem::HPos
int HPos
the horizontal position on the railway
Definition: TextUnit.h:48
TTrainController::StopTTClockMessage
void StopTTClockMessage(int Caller, AnsiString Message)
sends a message to the user and stops the timetable clock while it is displayed
Definition: TrainUnit.cpp:13794
TRailGraphics::gl103
Graphics::TBitmap * gl103
Definition: GraphicUnit.h:565
TAllRoutes::RemoveRouteElement
void RemoveRouteElement(int Caller, int HLoc, int VLoc, int ELink)
Erases the route element from Route2MultiMap and from the PrefDirVector.
Definition: TrackUnit.cpp:16393
TRailGraphics::sm83
Graphics::TBitmap * sm83
Definition: GraphicUnit.h:849
TRailGraphics::sm81
Graphics::TBitmap * sm81
Definition: GraphicUnit.h:847
TRailGraphics::bm74grounddblwhite
Graphics::TBitmap * bm74grounddblwhite
Definition: GraphicUnit.h:493
TAllRoutes::TLockedRouteClass::LastXLinkPos
int LastXLinkPos
the XLinkPos value of the last (i.e. most forward) element in the route
Definition: TrackUnit.h:1492
TRailGraphics::sm97
Graphics::TBitmap * sm97
Definition: GraphicUnit.h:865
TRailGraphics::Concourse
Graphics::TBitmap * Concourse
Definition: GraphicUnit.h:547
TOnePrefDir::LoadOldPrefDir
void LoadOldPrefDir(int Caller, std::ifstream &VecFile)
Old version of LoadPrefDir, used during development when the save format changed so the old files cou...
Definition: TrackUnit.cpp:10768
TTrackElement::FourAspect
@ FourAspect
Definition: TrackUnit.h:155
TRailGraphics::bm9
Graphics::TBitmap * bm9
Definition: GraphicUnit.h:512
TTrack::FindSetAndDisplayMatchingGap
bool FindSetAndDisplayMatchingGap(int Caller, int HLoc, int VLoc)
True if find an unset gap that matches the gap at HLoc & VLoc, if find one mark it with a green circl...
Definition: TrackUnit.cpp:3989
TTrack::CheckActiveLCVector
bool CheckActiveLCVector(int Caller, std::ifstream &VecFile)
Definition: TrackUnit.cpp:3248
TRailGraphics::gl67
Graphics::TBitmap * gl67
Definition: GraphicUnit.h:672
TRailGraphics::sm56
Graphics::TBitmap * sm56
Definition: GraphicUnit.h:823
TOneRoute::StartRoutePosition
int StartRoutePosition
TrackVectorPosition of the StartElement(s) set when the starting position of a new route is selected,...
Definition: TrackUnit.h:1395
TRailGraphics::bm69dblyellow
Graphics::TBitmap * bm69dblyellow
Definition: GraphicUnit.h:458
TRailGraphics::gl118
Graphics::TBitmap * gl118
Definition: GraphicUnit.h:581
TRailGraphics::sm105
Graphics::TBitmap * sm105
Definition: GraphicUnit.h:752
TRailGraphics::bm70dblyellow
Graphics::TBitmap * bm70dblyellow
Definition: GraphicUnit.h:465
TRailGraphics::sm24
Graphics::TBitmap * sm24
Definition: GraphicUnit.h:788
TTrack::CheckFootCrossingLinks
bool CheckFootCrossingLinks(int Caller, TTrackElement &TrackElement)
True if a footcrossing is linked properly at both ends.
Definition: TrackUnit.cpp:6777
TGraphicElement::SourceRect
TRect SourceRect
source rectangle of the original graphic
Definition: TrackUnit.h:356
TUtilities::LoadFileDouble
double LoadFileDouble(std::ifstream &InFile)
loads a double value from the file (converts from a string to a double) and uses the local decimal po...
Definition: Utilities.cpp:163
TRailGraphics::gl57
Graphics::TBitmap * gl57
Definition: GraphicUnit.h:661
TRailGraphics::gl120
Graphics::TBitmap * gl120
Definition: GraphicUnit.h:584
TTrack::ShowSelectedGap
void ShowSelectedGap(int Caller, TDisplay *Disp)
Called during gap setting to mark a gap with a red circle - after which the program awaits user selec...
Definition: TrackUnit.cpp:4148
TOnePrefDir::TPrefDir4MultiMapEntry
std::pair< THVPair, unsigned int > TPrefDir4MultiMapEntry
Definition: TrackUnit.h:1183
TTrack::OneNamedLocationElementAtLocation
bool OneNamedLocationElementAtLocation(int Caller, AnsiString LocationName)
True if there is at least one named location element with name 'LocationName', used in timetable inte...
Definition: TrackUnit.cpp:9188
TRailGraphics::gl5
Graphics::TBitmap * gl5
Definition: GraphicUnit.h:653
TRailGraphics::bm94unset
Graphics::TBitmap * bm94unset
Definition: GraphicUnit.h:516
TRailGraphics::sm93
Graphics::TBitmap * sm93
Definition: GraphicUnit.h:860
TTrack::CheckUserGraphics
bool CheckUserGraphics(int Caller, std::ifstream &InFile, UnicodeString GraphicsPath)
checks all user graphics & returns true for success
Definition: TrackUnit.cpp:3143
Unused
@ Unused
Definition: TrackUnit.h:63
TRailGraphics::gl122
Graphics::TBitmap * gl122
Definition: GraphicUnit.h:586
TRailGraphics::gl15
Graphics::TBitmap * gl15
Definition: GraphicUnit.h:616
TTrackElement::SigAspect
enum TTrackElement::@1 SigAspect
TOnePrefDir::TPrefDir4MultiMapIterator
std::multimap< THVPair, unsigned int, TMapComp >::iterator TPrefDir4MultiMapIterator
Definition: TrackUnit.h:1182
TRailGraphics::bm74
Graphics::TBitmap * bm74
Definition: GraphicUnit.h:489
TRailGraphics::gl90set
Graphics::TBitmap * gl90set
Definition: GraphicUnit.h:704
TAllRoutes::IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber
bool IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(int Caller, int TrackVectorPosition, int XLinkPos, TPrefDirElement &PrefDirElement, int &LockedVectorNumber)
Checks whether the preferred direction element at TrackVectorPosition with XLinkPos value is in a loc...
Definition: TrackUnit.cpp:16845
TrackUnit.h
TTrack::ReturnNextInactiveTrackElement
bool ReturnNextInactiveTrackElement(int Caller, TTrackElement &Next)
Return a reference to the inactive track element pointed to by NextTrackElementPtr (during zoomed-in ...
Definition: TrackUnit.cpp:2479
TRailGraphics::sm117
Graphics::TBitmap * sm117
Definition: GraphicUnit.h:762
TPrefDirElement::IsARoute
bool IsARoute
false for Pref Dir, true for route
Definition: TrackUnit.h:251
TAllRoutes::CheckRoutes
bool CheckRoutes(int Caller, int NumberOfActiveElements, std::ifstream &InFile)
Performs an integrity check on the routes stored in a session file and returns false if there is an e...
Definition: TrackUnit.cpp:17036
TTrack::Tag76Array
int Tag76Array[25][3]
these arrays give valid adjacent named element relative positions for each type of named element,...
Definition: TrackUnit.h:492
TTrack::LengthMarker
void LengthMarker(int Caller, TDisplay *Disp)
Examine all elements in the TrackVector and if have a valid length mark the relevant track using Mark...
Definition: TrackUnit.cpp:8096
TAllRoutes::LockedRouteLastTrackVectorPosition
unsigned int LockedRouteLastTrackVectorPosition
Definition: TrackUnit.h:1549
TOneRoute::RouteID
int RouteID
the ID number of the route, this is needed for session saves
Definition: TrackUnit.h:1393
TAllRoutes
Handles data and functions relating to all routes on the railway.
Definition: TrackUnit.h:1479
TPrefDirElement::TrackVectorPosition
int TrackVectorPosition
TrackVectorPosition of the corresponding track element.
Definition: TrackUnit.h:218
TRailGraphics::sm121
Graphics::TBitmap * sm121
Definition: GraphicUnit.h:909
TUserGraphicItem::VPos
int VPos
Definition: DisplayUnit.h:34
Utilities.h
TTrainController::TContinuationAutoSigVectorIterator
TContinuationAutoSigVector::iterator TContinuationAutoSigVectorIterator
Definition: TrainUnit.h:656
TGraphicElement::OriginalGraphic
Graphics::TBitmap * OriginalGraphic
Definition: TrackUnit.h:354
TRailGraphics::sm46
Graphics::TBitmap * sm46
Definition: GraphicUnit.h:812
TTrack::SaveTrack
void SaveTrack(int Caller, std::ofstream &VecFile, bool GraphicsFollow)
Save all active and inactive track elements to VecFile.
Definition: TrackUnit.cpp:2871
TOneRoute::SetLCChangeValues
void SetLCChangeValues(int Caller, bool ConsecSignalsRoute)
After a route has been selected successfully this function sets all LC change values appropriately fo...
Definition: TrackUnit.cpp:15420
TUserGraphicItem::HPos
int HPos
Definition: DisplayUnit.h:34
TDisplay::Update
void Update()
Repaint the screen display.
Definition: DisplayUnit.h:221
TRailGraphics::sm131striped
Graphics::TBitmap * sm131striped
Definition: GraphicUnit.h:769
TRailGraphics::gl63
Graphics::TBitmap * gl63
Definition: GraphicUnit.h:668
TRailGraphics::bm75grounddblwhite
Graphics::TBitmap * bm75grounddblwhite
Definition: GraphicUnit.h:499
TTrack::AdjElement
bool AdjElement(int Caller, int HLoc, int VLoc, int SpeedTag, int &FoundElement)
Definition: TrackUnit.cpp:7197
TOnePrefDir::EraseFromPrefDirVectorAnd4MultiMap
void EraseFromPrefDirVectorAnd4MultiMap(int Caller, int HLoc, int VLoc)
Erase element at HLoc and VLoc from the PrefDirVector and from the 4MultiMap. Note that this entails ...
Definition: TrackUnit.cpp:11030
Simple
@ Simple
Definition: TrackUnit.h:63
TTrack::GapFlashGreen
TGraphicElement * GapFlashGreen
Definition: TrackUnit.h:688
TRailGraphics::bm46
Graphics::TBitmap * bm46
Definition: GraphicUnit.h:443
TUtilities::RHSignalFlag
bool RHSignalFlag
new at v2.3.0 false=LH signals
Definition: Utilities.h:39
TRailGraphics::bm72dblyellow
Graphics::TBitmap * bm72dblyellow
Definition: GraphicUnit.h:477
TRailGraphics::sm22
Graphics::TBitmap * sm22
Definition: GraphicUnit.h:786
TTrack::NumberOfGaps
int NumberOfGaps(int Caller)
Returns the number of gaps in the railway.
Definition: TrackUnit.cpp:2495
TTrack::TSigElement::SigPtr
Graphics::TBitmap * SigPtr
pointer to the graphic
Definition: TrackUnit.h:625
TRailGraphics::BridgeNonSigRouteGraphicsPtr
Graphics::TBitmap * BridgeNonSigRouteGraphicsPtr[12]
route graphic for unrestricted route overlay
Definition: GraphicUnit.h:997
TAllRoutes::FindRouteNumberFromRoute2MultiMapNoErrors
bool FindRouteNumberFromRoute2MultiMapNoErrors(int Caller, int HLoc, int VLoc, int ELink, int &RouteNumber)
If a route is present at H, V & Elink returns true with RouteNumber giving vector position in AllRout...
Definition: TrackUnit.cpp:16144
TRailGraphics::sm130
Graphics::TBitmap * sm130
Definition: GraphicUnit.h:767
TRailGraphics::sm45
Graphics::TBitmap * sm45
Definition: GraphicUnit.h:811
TRailGraphics::bm38
Graphics::TBitmap * bm38
Definition: GraphicUnit.h:424
TOnePrefDir::TPrefDirVectorIterator
std::vector< TPrefDirElement >::iterator TPrefDirVectorIterator
Definition: TrackUnit.h:1215
TRailGraphics::gl90unset
Graphics::TBitmap * gl90unset
Definition: GraphicUnit.h:705
TOnePrefDir::CheckPrefDirAgainstTrackVectorNoMessage
bool CheckPrefDirAgainstTrackVectorNoMessage(int Caller)
Check loaded PrefDir against loaded track, and if discrepancies found clear EveryPrefDir & PrefDir4Mu...
Definition: TrackUnit.cpp:11258
TGraphicElement::TGraphicElement
TGraphicElement()
Default constructor (16 x 16 pixel element)
Definition: TrackUnit.cpp:1452
TRailGraphics::gl129Striped
Graphics::TBitmap * gl129Striped
Definition: GraphicUnit.h:594
TTrack::GetVectorPositionsFromInactiveTrackMap
TIMPair GetVectorPositionsFromInactiveTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
Similar to GetVectorPositionFromTrackMap but for inactive elements, a pair is returned because there ...
Definition: TrackUnit.cpp:5173
TRailGraphics::gl64
Graphics::TBitmap * gl64
Definition: GraphicUnit.h:669
TTrain
Definition: TrainUnit.h:271
TPrefDirElement::TPrefDirElement
TPrefDirElement()
Default constructor, loads default values.
Definition: TrackUnit.h:312
TOnePrefDir::PresetAutoRouteDiagonalFouledByTrack
bool PresetAutoRouteDiagonalFouledByTrack(int Caller, TPrefDirElement ElementIn, int XLink)
Called by GetStartAndEndPrefDirElements...
Definition: TrackUnit.cpp:11924
TRailGraphics::bm77Striped
Graphics::TBitmap * bm77Striped
Definition: GraphicUnit.h:503
TFixedTrackPiece::TFixedTrackPiece
TFixedTrackPiece()
Default constructor.
Definition: TrackUnit.cpp:95
TTrackElement::TrainIDOnBridgeTrackPos23
int TrainIDOnBridgeTrackPos23
Set to the TrainID value when a train is present on the element, bridges can have two trains present ...
Definition: TrackUnit.h:150
TOnePrefDir::GetFixedPrefDirElementAt
const TPrefDirElement & GetFixedPrefDirElementAt(int Caller, int At) const
Return a non-modifiable element at PrefDirVector position 'At'.
Definition: TrackUnit.cpp:9726
TRailGraphics::bm74grounddblred
Graphics::TBitmap * bm74grounddblred
Definition: GraphicUnit.h:492
TRailGraphics::gl1
Graphics::TBitmap * gl1
Definition: GraphicUnit.h:560
TTrack::LinkCheckArray
int LinkCheckArray[9][2]
array of valid link connecting values, I don't think this is used now
Definition: TrackUnit.h:488
TRailGraphics::sm66
Graphics::TBitmap * sm66
Definition: GraphicUnit.h:834
TTrack::TActiveLevelCrossing::VLoc
int VLoc
VLoc value for found level crossing element.
Definition: TrackUnit.h:541
TTrack::GetTruePositionsFromScreenPos
void GetTruePositionsFromScreenPos(int Caller, int &HPos, int &VPos, int ScreenPosH, int ScreenPosV)
Converse of GetScreenPositionsFromTruePos.
Definition: TrackUnit.cpp:6478
TRailGraphics::bm35
Graphics::TBitmap * bm35
Definition: GraphicUnit.h:415
TRailGraphics::bm10
Graphics::TBitmap * bm10
Definition: GraphicUnit.h:346
GapJump
@ GapJump
Definition: TrackUnit.h:63
TRailGraphics::bm45
Graphics::TBitmap * bm45
Definition: GraphicUnit.h:442
TRailGraphics::sm19
Graphics::TBitmap * sm19
Definition: GraphicUnit.h:782
TAllRoutes::AddRouteElement
void AddRouteElement(int Caller, int HLoc, int VLoc, int ELink, int RouteNumber, TPrefDirElement RouteElement)
A single TPrefDirElement is added to both PrefDirVector (for the route at RouteNumber) and Route2Mult...
Definition: TrackUnit.cpp:16503
TOneRoute::SetRouteSearchVectorGraphics
void SetRouteSearchVectorGraphics(int Caller, bool AutoSigsFlag, bool ConsecSignalsRoute)
Set values for EXGraphicPtr and EntryDirectionGraphicPtr for all elements in SearchVector so that the...
Definition: TrackUnit.cpp:15369
TRailGraphics::sm82
Graphics::TBitmap * sm82
Definition: GraphicUnit.h:848
TTrackElement::Length01
int Length01
Definition: TrackUnit.h:146
TRailGraphics::bm71dblyellow
Graphics::TBitmap * bm71dblyellow
Definition: GraphicUnit.h:471
TRailGraphics::sm124
Graphics::TBitmap * sm124
Definition: GraphicUnit.h:912
TRailGraphics::bm69CallingOn
Graphics::TBitmap * bm69CallingOn
Definition: GraphicUnit.h:457
TTrackElement::SpeedLimit01
int SpeedLimit01
Definition: TrackUnit.h:146
TTrack::Raising
@ Raising
Definition: TrackUnit.h:522
TRailGraphics::gl26
Graphics::TBitmap * gl26
Definition: GraphicUnit.h:627
TTrack::VLocMax
int VLocMax
give extent of railway for use in zoomed in and out displays and in saving railway images
Definition: TrackUnit.h:486
TTrack::UserGraphicMove
void UserGraphicMove(int Caller, int HPosInput, int VPosInput, int &UserGraphicItem, int &UserGraphicMoveHPos, int &UserGraphicMoveVPos, bool &UserGraphicFoundFlag)
handles moving of user graphics
Definition: TrackUnit.cpp:8823
TTextHandler::FindText
bool FindText(int Caller, AnsiString Name, int &HPos, int &VPos)
look in TextVector for text item 'Name', and if found return true and return its position in &HPos an...
Definition: TextUnit.cpp:551
TDisplay::DisplayOffsetV
static int DisplayOffsetV
the vertical offset of the displayed screen
Definition: DisplayUnit.h:78
TOneRoute::StartElement2
TPrefDirElement StartElement2
the two preferred direction elements corresponding to the starting position of a new route
Definition: TrackUnit.h:1397
TOneRoute::TRouteFlashElement::VLoc
int VLoc
Definition: TrackUnit.h:1361
TOneRoute::SetRouteFlashValues
void SetRouteFlashValues(int Caller, bool AutoSigsFlag, bool ConsecSignalsRoute)
After a route has been selected successfully this function sets all RouteFlash (see above) values app...
Definition: TrackUnit.cpp:15392
TRailGraphics::gl86
Graphics::TBitmap * gl86
Definition: GraphicUnit.h:697
TRailGraphics::bm134
Graphics::TBitmap * bm134
Definition: GraphicUnit.h:365
TTrainController::BaseTime
TDateTime BaseTime
CurrentDateTime (i.e. real time) when operation restarts after a pause.
Definition: TrainUnit.h:631
TTrack::Tag129Array
int Tag129Array[8][3]
Definition: TrackUnit.h:498
TTrack::InactiveTrack2MultiMap
TInactiveTrack2MultiMap InactiveTrack2MultiMap
multimap of inactive TrackElements (see type for more information above)
Definition: TrackUnit.h:690
TRailGraphics::bm14
Graphics::TBitmap * bm14
Definition: GraphicUnit.h:385
TRailGraphics::sm106
Graphics::TBitmap * sm106
Definition: GraphicUnit.h:753
TRailGraphics::bm68dblyellow
Graphics::TBitmap * bm68dblyellow
Definition: GraphicUnit.h:452
TRailGraphics::gl97
Graphics::TBitmap * gl97
Definition: GraphicUnit.h:714
TOnePrefDir::PrefDirSize
unsigned int PrefDirSize() const
Return the vector size.
Definition: TrackUnit.h:1259
TTrack::PlotSignal
void PlotSignal(int Caller, TTrackElement TrackElement, TDisplay *Disp)
Plot signals on screen according to their aspect (Attribute value)
Definition: TrackUnit.cpp:5404
End
@ End
Definition: TrackUnit.h:72
TUserGraphicItem
Definition: DisplayUnit.h:31
TOneRoute::RouteFlash
TRouteFlash RouteFlash
the class member that allows the route to flash during setting up (see TRouteFlash above)
Definition: TrackUnit.h:1399
TRailGraphics::gl62
Graphics::TBitmap * gl62
Definition: GraphicUnit.h:667
TRailGraphics::sm67
Graphics::TBitmap * sm67
Definition: GraphicUnit.h:835
TTrack::TActiveLevelCrossing::BarrierState
TBarrierState BarrierState
state of barriers
Definition: TrackUnit.h:533
TTrack::TimetabledLocationNameAllocated
bool TimetabledLocationNameAllocated(int Caller, AnsiString LocationName)
True if a non-empty LocationName found as a timetabled location name i.e. not as a continuation name.
Definition: TrackUnit.cpp:7401
TRailGraphics::sm9
Graphics::TBitmap * sm9
Definition: GraphicUnit.h:856
TTrack::LCFoundInAutoSigsRouteMessageGiven
bool LCFoundInAutoSigsRouteMessageGiven
true if message given to user, to avoid giving multiple times and to avoid other failure messages bei...
Definition: TrackUnit.h:650
TRailGraphics::sm68
Graphics::TBitmap * sm68
Definition: GraphicUnit.h:895
clB0G0R5
#define clB0G0R5
Definition: GraphicUnit.h:41
TTrack::TrackFinished
bool TrackFinished
marker for all Conn & ConnLinkPos values set & track complete
Definition: TrackUnit.h:481
TTrack::InactiveTrackElementAt
TTrackElement & InactiveTrackElementAt(int Caller, int At)
A range-checked version of InactiveTrackElement.at(At)
Definition: TrackUnit.cpp:8929
TRailGraphics::LinkNonSigRouteGraphicsPtr
Graphics::TBitmap * LinkNonSigRouteGraphicsPtr[30]
unrestricted route graphic overlay
Definition: GraphicUnit.h:1010
TPrefDirElement::GetTrackVectorPosition
unsigned int GetTrackVectorPosition() const
Returns TrackVectorPosition.
Definition: TrackUnit.h:294
TRailGraphics::sm28
Graphics::TBitmap * sm28
Definition: GraphicUnit.h:792
TTrack::RouteFailMessage
AnsiString RouteFailMessage
Definition: TrackUnit.h:638
clB0G5R0
#define clB0G5R0
Definition: GraphicUnit.h:71
TTrack::LNPendingList
TLNPendingList LNPendingList
list of location name elements awaiting processing (see type for more information above)
Definition: TrackUnit.h:696
TRailGraphics::gl114
Graphics::TBitmap * gl114
Definition: GraphicUnit.h:577
TRailGraphics::sm116
Graphics::TBitmap * sm116
Definition: GraphicUnit.h:905
TTrackElement
Basic track elements as implemented in the overall railway layout.
Definition: TrackUnit.h:122
TRailGraphics::LCLHSVer
Graphics::TBitmap * LCLHSVer
Definition: GraphicUnit.h:722
TRailGraphics::bm74dblyellow
Graphics::TBitmap * bm74dblyellow
Definition: GraphicUnit.h:491
TRailGraphics::sm103
Graphics::TBitmap * sm103
Definition: GraphicUnit.h:750
TTrack::RebuildUserGraphics
void RebuildUserGraphics(int Caller, TDisplay *Disp)
rebuild user graphics
Definition: TrackUnit.cpp:3407
TRailGraphics::bmSolidBgnd
Graphics::TBitmap * bmSolidBgnd
Definition: GraphicUnit.h:981
TTrack::GroundSignalBuild
@ GroundSignalBuild
Definition: TrackUnit.h:752
TRailGraphics::smSolidBgnd
Graphics::TBitmap * smSolidBgnd
Definition: GraphicUnit.h:982
TRailGraphics::bmNameStriped
Graphics::TBitmap * bmNameStriped
Definition: GraphicUnit.h:524
TRailGraphics::gl88unset
Graphics::TBitmap * gl88unset
Definition: GraphicUnit.h:700
SignalPost
@ SignalPost
Definition: TrackUnit.h:63
TTrack::SetAllDefaultLengthsAndSpeedLimits
void SetAllDefaultLengthsAndSpeedLimits(int Caller)
Work through all elements in TrackVector setting all lengths & speed limits to default values - inclu...
Definition: TrackUnit.cpp:8061
TRailGraphics::BridgeGraphicsPtr
Graphics::TBitmap * BridgeGraphicsPtr[12]
basic graphic for use in plotting the original graphic during route flashing
Definition: GraphicUnit.h:991
TRailGraphics::bm69green
Graphics::TBitmap * bm69green
Definition: GraphicUnit.h:461
TAllRoutes::WriteAllRoutesToImage
void WriteAllRoutesToImage(int Caller, Graphics::TBitmap *Bitmap)
Calls RouteImageMarker for each route in turn to display the route colours and direction arrows on th...
Definition: TrackUnit.cpp:15546
IDInt::GetInt
int GetInt() const
get the internal integer
Definition: TrackUnit.h:420
TRailGraphics::sm132
Graphics::TBitmap * sm132
Definition: GraphicUnit.h:770
TPrefDirElement::operator!=
bool operator!=(TPrefDirElement RHElement)
non-equivalence operator
Definition: TrackUnit.cpp:862
TAllRoutes::TRoute2MultiMapIterator
TRoute2MultiMap::iterator TRoute2MultiMapIterator
Definition: TrackUnit.h:1515
TRailGraphics::sm20
Graphics::TBitmap * sm20
Definition: GraphicUnit.h:784
TRailGraphics::sm52
Graphics::TBitmap * sm52
Definition: GraphicUnit.h:819
TTrack::GetScreenPositionsFromTruePos
void GetScreenPositionsFromTruePos(int Caller, int &ScreenPosH, int &ScreenPosV, int HPosTrue, int VPosTrue)
With large railways only part of the railway is displayed on screen, and this function converts true ...
Definition: TrackUnit.cpp:6492
TRailGraphics::bm68yellow
Graphics::TBitmap * bm68yellow
Definition: GraphicUnit.h:456
TTrack::TInactiveTrackRange
std::pair< TInactiveTrack2MultiMapIterator, TInactiveTrack2MultiMapIterator > TInactiveTrackRange
Definition: TrackUnit.h:582
TRailGraphics::bm31
Graphics::TBitmap * bm31
Definition: GraphicUnit.h:403
TPrefDirElement::AutoSignals
bool AutoSignals
marker within the route for an AutoSignal route element
Definition: TrackUnit.h:253
TRailGraphics::bm74CallingOn
Graphics::TBitmap * bm74CallingOn
Definition: GraphicUnit.h:490
TRailGraphics::gl76
Graphics::TBitmap * gl76
Definition: GraphicUnit.h:684
FirstUnusedSpeedTagNumber
#define FirstUnusedSpeedTagNumber
Definition: TrackUnit.h:36
TTrack::EraseLocationAndActiveTrackElementNames
void EraseLocationAndActiveTrackElementNames(int Caller, AnsiString LocationName)
Examines LocationNameMultiMap and if the LocationName is found all elements at that H & V (in both ac...
Definition: TrackUnit.cpp:7439
TRailGraphics::sm71
Graphics::TBitmap * sm71
Definition: GraphicUnit.h:898
TRailGraphics::sm43
Graphics::TBitmap * sm43
Definition: GraphicUnit.h:809
TAllRoutes::MarkAllRoutes
void MarkAllRoutes(int Caller, TDisplay *Disp)
Calls PrefDirMarker for all routes, with RouteCall set to identify a route call, and BuildingPrefDir ...
Definition: TrackUnit.cpp:15531
TRailGraphics::sm101
Graphics::TBitmap * sm101
Definition: GraphicUnit.h:748
Concourse
@ Concourse
Definition: TrackUnit.h:65
TTrack::BotPlatAllowed
Set< int, 1, 146 > BotPlatAllowed
Definition: TrackUnit.h:504
TRailGraphics::gl52
Graphics::TBitmap * gl52
Definition: GraphicUnit.h:656
TTrack::SelectVector
TTrackVector SelectVector
vectors of TrackElements
Definition: TrackUnit.h:705
TRailGraphics::sm29
Graphics::TBitmap * sm29
Definition: GraphicUnit.h:793
TConfiguration
TConfiguration
< describes the type of track link. 'End' is used for both buffer stop and continuation entry/exit po...
Definition: TrackUnit.h:71
TOnePrefDir::WritePrefDirToImage
void WritePrefDirToImage(int Caller, Graphics::TBitmap *Bitmap)
Used when creating a bitmap image to display preferred directions (as on screen during 'Set preferred...
Definition: TrackUnit.cpp:11714
TOnePrefDir::DecrementPrefDirElementNumbersInPrefDir4MultiMap
void DecrementPrefDirElementNumbersInPrefDir4MultiMap(int Caller, unsigned int ErasedElementNumber)
Called after ErasePrefDirElementAt to decrement the remaining PrefDirElementNumbers in 4MultiMap if t...
Definition: TrackUnit.cpp:11452
TTrackElement::LogTrack
AnsiString LogTrack(int Caller) const
Used to log track parameters for call stack logging.
Definition: TrackUnit.cpp:201
TRailGraphics::gl95unset
Graphics::TBitmap * gl95unset
Definition: GraphicUnit.h:713
TTrack::TrackVectorSize
int TrackVectorSize()
Return the number of active track elements.
Definition: TrackUnit.h:801
TTrackType
TTrackType
< describes the type of track element
Definition: TrackUnit.h:62
TRailGraphics::bm77
Graphics::TBitmap * bm77
Definition: GraphicUnit.h:502
TTrack::NoGaps
bool NoGaps(int Caller)
True if there are no gaps.
Definition: TrackUnit.cpp:4073
TGraphicElement::PlotOriginal
void PlotOriginal(int Caller, TDisplay *Disp)
Plot the original graphic on screen.
Definition: TrackUnit.cpp:1596
TextHandler
TTextHandler * TextHandler
Definition: TextUnit.cpp:94
TRailGraphics::bm39
Graphics::TBitmap * bm39
Definition: GraphicUnit.h:427
TRailGraphics::sm40
Graphics::TBitmap * sm40
Definition: GraphicUnit.h:806
TRailGraphics::bm41
Graphics::TBitmap * bm41
Definition: GraphicUnit.h:433
TRailGraphics::sm54
Graphics::TBitmap * sm54
Definition: GraphicUnit.h:821
TRailGraphics::bm72green
Graphics::TBitmap * bm72green
Definition: GraphicUnit.h:480
TRailGraphics::gl129
Graphics::TBitmap * gl129
Definition: GraphicUnit.h:593
TRailGraphics::sm31
Graphics::TBitmap * sm31
Definition: GraphicUnit.h:796
TGraphicElement::ExistingGraphicLoaded
bool ExistingGraphicLoaded
state flags
Definition: TrackUnit.h:348
TRailGraphics::bm74green
Graphics::TBitmap * bm74green
Definition: GraphicUnit.h:494
TUserGraphicItem::Width
int Width
Definition: DisplayUnit.h:35
TTrack::MirrorArray
int MirrorArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'mirroring' via menu items 'Edit' & 'Mirror'
Definition: TrackUnit.h:670
TRailGraphics::bm71grounddblred
Graphics::TBitmap * bm71grounddblred
Definition: GraphicUnit.h:472
Utilities
TUtilities * Utilities
Definition: Utilities.cpp:46
TFixedTrackPiece::SmallGraphicPtr
Graphics::TBitmap * SmallGraphicPtr
the track bitmap for display on the zoomed-out railway
Definition: TrackUnit.h:91
TRailGraphics::bm40
Graphics::TBitmap * bm40
Definition: GraphicUnit.h:430
TRailGraphics::sm42
Graphics::TBitmap * sm42
Definition: GraphicUnit.h:808
TRailGraphics::gl111
Graphics::TBitmap * gl111
Definition: GraphicUnit.h:574
TTrack::IsATrackElementAdjacentToLink
bool IsATrackElementAdjacentToLink(int Caller, int HLocIn, int VLocIn, int LinkIn)
True if there is an element adjacent to LinkIn for element at HLoc & VLoc.
Definition: TrackUnit.cpp:9373
TTrackElement::TempMarker
bool TempMarker
Utility marker for program use.
Definition: TrackUnit.h:134
TAllRoutes::DecrementRouteNumbersInRoute2MultiMap
void DecrementRouteNumbersInRoute2MultiMap(int Caller, int RouteNumber)
After a route has been erased from AllRoutesVector and its entries from Route2MultiMap,...
Definition: TrackUnit.cpp:16350
TTrack::TActiveLevelCrossing::TrainPassed
bool TrainPassed
marker that is set when a train is present on one of the elements of the LC - used to provide a 3 min...
Definition: TrackUnit.h:531
TOneRoute::GetRouteTruncateElement
void GetRouteTruncateElement(int Caller, int HLoc, int VLoc, bool ConsecSignalsRoute, TTruncateReturnType &ReturnFlag)
Examines the route to see whether the element at H & V is in the route, and if not returns a ReturnFl...
Definition: TrackUnit.cpp:15121
TTrack::BuildGapMapFromTrackVector
void BuildGapMapFromTrackVector(int Caller)
Examine TrackVector and whenever find a new gap pair enter it into GapMap.
Definition: TrackUnit.cpp:4306
TTrackElement::ThreeAspect
@ ThreeAspect
Definition: TrackUnit.h:155
TTrack::NoActiveOrInactiveTrack
bool NoActiveOrInactiveTrack(int Caller)
True if there is no active or inactive track in the railway.
Definition: TrackUnit.cpp:1615
TRailGraphics::gl68
Graphics::TBitmap * gl68
Definition: GraphicUnit.h:673
TRailGraphics::sm18
Graphics::TBitmap * sm18
Definition: GraphicUnit.h:781
TRailGraphics::sm128
Graphics::TBitmap * sm128
Definition: GraphicUnit.h:916
TTrack::FixedTrackArray
TFixedTrackArray FixedTrackArray
the FixedTrackPiece array object
Definition: TrackUnit.h:476
TDisplay::DisplayZoomOutOffsetVHome
static int DisplayZoomOutOffsetVHome
the vertical offset of the zoomed-out 'Home' display
Definition: DisplayUnit.h:90
TRailGraphics::gl121
Graphics::TBitmap * gl121
Definition: GraphicUnit.h:585
TRailGraphics::LCBothHor
Graphics::TBitmap * LCBothHor
Definition: GraphicUnit.h:719
TRailGraphics::sm6
Graphics::TBitmap * sm6
Definition: GraphicUnit.h:827
TPrefDirElement::GetOriginalGraphicPtr
Graphics::TBitmap * GetOriginalGraphicPtr()
picks up the original (non-flashing) graphic for use during route flashing
Definition: TrackUnit.cpp:381
TTrack::DiagonalFouledByTrain
bool DiagonalFouledByTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber, int &TrainID)
Definition: TrackUnit.cpp:9608
TAllRoutes::IsThereARouteAtIDNumber
bool IsThereARouteAtIDNumber(int Caller, IDInt RouteID)
Returns true if there is a route with the given ID number - added at v1.3.1 (see function for details...
Definition: TrackUnit.cpp:16942
TTrack::NameAllowed
Set< int, 1, 146 > NameAllowed
Definition: TrackUnit.h:504
TRailGraphics::LinkSigRouteGraphicsPtr
Graphics::TBitmap * LinkSigRouteGraphicsPtr[30]
preferred direction route graphic overlay
Definition: GraphicUnit.h:1008
TRailGraphics::gl142
Graphics::TBitmap * gl142
Definition: GraphicUnit.h:610
TTrack::ReturnNextTrackElement
bool ReturnNextTrackElement(int Caller, TTrackElement &Next)
Return a reference to the active track element pointed to by NextTrackElementPtr (during zoomed-in or...
Definition: TrackUnit.cpp:2463
TRailGraphics::gl92unset
Graphics::TBitmap * gl92unset
Definition: GraphicUnit.h:709
TOneRoute::ClearRoute
void ClearRoute()
Empty the route of any stored elements.
Definition: TrackUnit.h:1405
TTrack::ResetAllTrainIDElements
void ResetAllTrainIDElements(int Caller)
Track elements have members that indicates whether and on what track a train is present (TrainIDOnEle...
Definition: TrackUnit.cpp:6449
TOneRoute::RouteImageMarker
void RouteImageMarker(int Caller, Graphics::TBitmap *Bitmap) const
Used when creating a bitmap image to display the route colours and direction arrows (as on screen dur...
Definition: TrackUnit.cpp:12954
TTrack::IsLCBarrierUpAtHV
bool IsLCBarrierUpAtHV(int Caller, int HLoc, int VLoc)
True if a closed (to trains) level crossing is found at H & V.
Definition: TrackUnit.cpp:6198
TTrack::LocationNameAllocated
bool LocationNameAllocated(int Caller, AnsiString LocationName)
True if a non-empty LocationName found in LocationNameMultiMap.
Definition: TrackUnit.cpp:7387
TTrack::SetLCAttributeAtHV
void SetLCAttributeAtHV(int Caller, int HLoc, int VLoc, int Attr)
Set LC attribute at H & V; 0=closed to trains, 1 = open to trains, 2 = changing state = closed to tra...
Definition: TrackUnit.cpp:6277
TRailGraphics::gl61
Graphics::TBitmap * gl61
Definition: GraphicUnit.h:666
TRailGraphics::LCBotHor
Graphics::TBitmap * LCBotHor
Definition: GraphicUnit.h:720
TTrack::TLocationNameMultiMapEntry
std::pair< AnsiString, int > TLocationNameMultiMapEntry
Definition: TrackUnit.h:606
TRailGraphics::gl55
Graphics::TBitmap * gl55
Definition: GraphicUnit.h:659
TUtilities::CallLogPop
void CallLogPop(int Caller)
pops the last entry off the call stack, throws an error if called when empty
Definition: Utilities.cpp:49
TTrain::MaximumSpeedLimit
static const int MaximumSpeedLimit
km/h
Definition: TrainUnit.h:284
TTrack::TLNDone2MultiMapIterator
TLNDone2MultiMap::iterator TLNDone2MultiMapIterator
during naming of linked named location elements, '2' because there
Definition: TrackUnit.h:597
TOnePrefDir::PrefDir4MultiMap
TPrefDir4MultiMap PrefDir4MultiMap
the pref dir multimap - up to 4 values (up to 2 tracks per element each with 2 directions)
Definition: TrackUnit.h:1185
TTrack::ThreeAspectBuild
@ ThreeAspectBuild
Definition: TrackUnit.h:752
TRailGraphics::sm30
Graphics::TBitmap * sm30
Definition: GraphicUnit.h:795
TRailGraphics::bm85
Graphics::TBitmap * bm85
Definition: GraphicUnit.h:509
TRailGraphics::sm3
Graphics::TBitmap * sm3
Definition: GraphicUnit.h:794
TRailGraphics::bm70yellow
Graphics::TBitmap * bm70yellow
Definition: GraphicUnit.h:469
TOnePrefDir::GetVectorPositionsFromPrefDir4MultiMap
void GetVectorPositionsFromPrefDir4MultiMap(int Caller, int HLoc, int VLoc, bool &FoundFlag, int &PrefDirPos0, int &PrefDirPos1, int &PrefDirPos2, int &PrefDirPos3)
Return up to 4 vector positions for a given HLoc & VLoc; unused values return -1.
Definition: TrackUnit.cpp:11342
TRailGraphics::sm110
Graphics::TBitmap * sm110
Definition: GraphicUnit.h:758
TRailGraphics::sm92
Graphics::TBitmap * sm92
Definition: GraphicUnit.h:859
TOnePrefDir::GetPrefDirTruncateElement
bool GetPrefDirTruncateElement(int Caller, int HLoc, int VLoc)
Called during PrefDir build or distance setting. It truncates at & including the first element in the...
Definition: TrackUnit.cpp:10517
TAllRoutes::TRoute2MultiMapEntry
std::pair< THVPair, TRouteElementPair > TRoute2MultiMapEntry
Definition: TrackUnit.h:1516
TDisplay::PlotOutput
void PlotOutput(int Caller, int HPos, int VPos, Graphics::TBitmap *PlotItem)
Plot the graphic at screen position HPos & VPos.
Definition: DisplayUnit.cpp:86
TAllRoutes::AllRoutesVector
TAllRoutesVector AllRoutesVector
the vector that stores all the routes on the railway
Definition: TrackUnit.h:1568
TUtilities::SaveFileBool
void SaveFileBool(std::ofstream &OutFile, bool SaveBool)
stores '1' if the bool is true or '0' if false to the file, then a CR
Definition: Utilities.cpp:107
TRailGraphics::sm69
Graphics::TBitmap * sm69
Definition: GraphicUnit.h:896
TRailGraphics::gl123
Graphics::TBitmap * gl123
Definition: GraphicUnit.h:587
TOnePrefDir::SaveSearchVector
void SaveSearchVector(int Caller, std::ofstream &VecFile)
Save the search vector to a file.
Definition: TrackUnit.cpp:10997
TOneRoute::GetNextPreferredRouteElement
bool GetNextPreferredRouteElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool ConsecSignalsRoute, bool AutoSigsFlag, IDInt &ReqPosRouteID, bool &PointsChanged)
Try to find a set of linked tracks that lie on preferred directions between the route start element a...
Definition: TrackUnit.cpp:12536
TRailGraphics::gl48
Graphics::TBitmap * gl48
Definition: GraphicUnit.h:651
TOneRoute::ForceCancelRoute
void ForceCancelRoute(int Caller)
Cancel a route immediately if a train occupies it when travelling in the wrong direction (or occupies...
Definition: TrackUnit.cpp:15325
TTrack::SaveChangingLCVector
void SaveChangingLCVector(int Caller, std::ofstream &OutFile)
Save all changing vector values (used for error file)
Definition: TrackUnit.cpp:3225
TTrackElement::PlotVariableTrackElement
void PlotVariableTrackElement(int Caller, TDisplay *Disp) const
Plot the element on the display 'variable' indicates that the element may be named and if so may be p...
Definition: TrackUnit.cpp:140
TOnePrefDir::StorePrefDirElement
void StorePrefDirElement(int Caller, TPrefDirElement LoadPrefDirElement)
Store a single pref dir element in the vector & map.
Definition: TrackUnit.cpp:11405
TTrack::SaveUserGraphics
void SaveUserGraphics(int Caller, std::ofstream &VecFile)
save graphics
Definition: TrackUnit.cpp:9655
TTrack::ThisNamedLocationLongEnoughForSplit
bool ThisNamedLocationLongEnoughForSplit(int Caller, AnsiString LocationName, int FirstNamedElementPos, int &SecondNamedElementPos, int &FirstNamedLinkedElementPos, int &SecondNamedLinkedElementPos)
See above under 'OneNamedLocationLongEnoughForSplit'.
Definition: TrackUnit.cpp:9061
TGraphicElement::LoadOriginalScreenGraphic
void LoadOriginalScreenGraphic(int Caller)
Load original graphic from the screen for point flashing or route start markers.
Definition: TrackUnit.cpp:1498
TRailGraphics::sm109
Graphics::TBitmap * sm109
Definition: GraphicUnit.h:756
TTrack::SelectVectorSize
unsigned int SelectVectorSize()
Return the number of selected active and inactive track elements (via menu items 'Edit' and 'Select')
Definition: TrackUnit.h:813
TTrack::PlotLoweredLinkedLevelCrossingBarriers
void PlotLoweredLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, bool ConsecSignals, TDisplay *Disp)
Plot & open (to trains) all level crossings linked to TrackElement.
Definition: TrackUnit.cpp:5611
TPrefDirElement::GetRouteGraphicPtr
Graphics::TBitmap * GetRouteGraphicPtr(bool AutoSigsFlag, bool ConsecSignalsRoute)
picks up the appropriate route graphic
Definition: TrackUnit.cpp:531
TRailGraphics::bm74yellow
Graphics::TBitmap * bm74yellow
Definition: GraphicUnit.h:495
TTrack::Tag78Array
int Tag78Array[25][3]
Definition: TrackUnit.h:495
TTrack::PlotGap
void PlotGap(int Caller, TTrackElement TrackElement, TDisplay *Disp)
Plots a gap on screen - may be set or unset.
Definition: TrackUnit.cpp:5267
TPrefDirElement::GetDirectionPrefDirGraphicPtr
Graphics::TBitmap * GetDirectionPrefDirGraphicPtr() const
picks up the EntryDirectionGraphicPtr for preferred directions
Definition: TrackUnit.cpp:812
TOnePrefDir::LoadPrefDir
void LoadPrefDir(int Caller, std::ifstream &VecFile)
Load a vector and map of preferred directions from the file.
Definition: TrackUnit.cpp:10817
Under
@ Under
Definition: TrackUnit.h:72
TRailGraphics::bm59
Graphics::TBitmap * bm59
Definition: GraphicUnit.h:449
TOneRoute::PointsToBeChanged
bool PointsToBeChanged(int Caller) const
Called by GetNextNonPreferredRouteElement and GetNextPreferredRouteElement to check whether or not an...
Definition: TrackUnit.cpp:14877
TTrack::TrackVector
TTrackVector TrackVector
Definition: TrackUnit.h:705
TRailGraphics::gl84
Graphics::TBitmap * gl84
Definition: GraphicUnit.h:695
TTrack::TActiveLevelCrossing::BaseElementSpeedTag
int BaseElementSpeedTag
SpeedTag value for the base element of a level crossing.
Definition: TrackUnit.h:537
TTrackElement::operator!=
bool operator!=(TTrackElement RHElement)
non-equivalence operator
Definition: TrackUnit.cpp:130
TTrack::ResetConnClkCheckUnsetGapJumps
bool ResetConnClkCheckUnsetGapJumps(int Caller)
Sets all Conns and CLks to -1 except for gapjumps that match and are properly set,...
Definition: TrackUnit.cpp:2516
TOnePrefDir::GetModifiablePrefDirElementAt
TPrefDirElement & GetModifiablePrefDirElementAt(int Caller, int At)
Return a modifiable element at PrefDirVector position 'At'.
Definition: TrackUnit.cpp:9738
TOnePrefDir::SearchForPrefDir
bool SearchForPrefDir(int Caller, TTrackElement TrackElement, int XLinkPos, int RequiredPosition)
Try to find a selected element from a given start position. Enter with CurrentTrackElement stored in ...
Definition: TrackUnit.cpp:10060
TRailGraphics::sm96
Graphics::TBitmap * sm96
Definition: GraphicUnit.h:863
TGraphicElement
Allows a single Width x Height graphic to change and change back independently of the remaining displ...
Definition: TrackUnit.h:345
TTrackElement::CallingOnSet
bool CallingOnSet
Used for for signals only when a train is being called on - used to plot the position lights.
Definition: TrackUnit.h:132
TUtilities::SaveFileInt
void SaveFileInt(std::ofstream &OutFile, int SaveInt)
stores the int value to the file, then a CR
Definition: Utilities.cpp:116
TrainController
TTrainController * TrainController
the object pointer, one object only - created in InterfaceUnit
Definition: TrainUnit.cpp:53
TTrack::OneNamedLocationLongEnoughForSplit
bool OneNamedLocationLongEnoughForSplit(int Caller, AnsiString LocationName)
Definition: TrackUnit.cpp:8964
Lead
@ Lead
Definition: TrackUnit.h:72
TTrack::TrackElementPresentAtHV
bool TrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
New at v1.2.0; true if a track element present (not inactive elements - see InactiveTrackElementPrese...
Definition: TrackUnit.cpp:5132
TGraphicElement::LoadOriginalExistingGraphic
void LoadOriginalExistingGraphic(int Caller, int HOffset, int VOffset, int WidthIn, int HeightIn, Graphics::TBitmap *Graphic)
Load red or green gap flashing graphic from the stored bitmaps.
Definition: TrackUnit.cpp:1532
TOnePrefDir::CalcDistanceAndSpeed
void CalcDistanceAndSpeed(int Caller, int &OverallDistance, int &OverallSpeedLimit, bool &LeadingPointsAtLastElement)
Used when setting element lengths, returns in &OverallDistance the overall distance for the selected ...
Definition: TrackUnit.cpp:11651
TTrack::GetHLocMin
int GetHLocMin()
Definition: TrackUnit.h:770
TTextHandler::TextPtrAt
TTextItem * TextPtrAt(int Caller, int At)
return the text item at position 'At' in TextVector (carries out range checking)
Definition: TextUnit.cpp:521
TTrack::WriteTrackToImage
void WriteTrackToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by TInterface::SaveImageNoGrid1Click, TInterface::SaveImageAndGrid1Click and TInterface::SaveI...
Definition: TrackUnit.cpp:3433
TUtilities::CheckFileInt
bool CheckFileInt(std::ifstream &InFile, int Lowest, int Highest)
checks that the value is an int lying between Lowest & Highest (inclusive), returns true for success
Definition: Utilities.cpp:216
TTrack::TrackPush
void TrackPush(int Caller, TTrackElement TrackElement)
Insert TrackElement into the relevant vector and map, and, if named, insert the name in LocationNameM...
Definition: TrackUnit.cpp:4964
TFixedTrackPiece::FixedNamedLocationElement
bool FixedNamedLocationElement
true for an element that can be named (platforms, concourse, footcrossings & non-station named loacti...
Definition: TrackUnit.h:82
TOnePrefDir::PrefDirSearchLimit
static const int PrefDirSearchLimit
limit to the number of elements searched in attempting to find a preferred direction
Definition: TrackUnit.h:1218
TTrack::GetTrackVectorIteratorFromNamePosition
TTrackVectorIterator GetTrackVectorIteratorFromNamePosition(int Caller, int Position)
Takes an adjusted vector position value from either vector (if active, Position = -TruePos -1,...
Definition: TrackUnit.cpp:7873
TRailGraphics::bm70grounddblwhite
Graphics::TBitmap * bm70grounddblwhite
Definition: GraphicUnit.h:467
TRailGraphics::bm70green
Graphics::TBitmap * bm70green
Definition: GraphicUnit.h:468
TRailGraphics::gl115
Graphics::TBitmap * gl115
Definition: GraphicUnit.h:578
TTrack::Up
@ Up
Definition: TrackUnit.h:522
TRailGraphics::sm89
Graphics::TBitmap * sm89
Definition: GraphicUnit.h:855
TTrack::NextTrackElementPtr
TTrackVectorIterator NextTrackElementPtr
track vector iterator used during cycling through a track vector
Definition: TrackUnit.h:707
TTrack::Tag130Array
int Tag130Array[8][3]
Definition: TrackUnit.h:499
TTrack::BlankElementAt
bool BlankElementAt(int Caller, int At) const
Definition: TrackUnit.cpp:8943
TRailGraphics::sm127
Graphics::TBitmap * sm127
Definition: GraphicUnit.h:915
TOneRoute
A descendent of TOnePrefDir used for routes. Used during contruction of a route (ConstructRoute) and ...
Definition: TrackUnit.h:1355
TDisplay::PlotSignalBlankOnBitmap
void PlotSignalBlankOnBitmap(int HLoc, int VLoc, int SpeedTag, Graphics::TBitmap *Bitmap, bool RHSFlag)
Definition: DisplayUnit.cpp:340
TTrack::NamedLocationElementAt
bool NamedLocationElementAt(int Caller, int HLoc, int VLoc)
True if the active or inactive TrackElement at HLoc & VLoc has its FixedNamedLocationElement member t...
Definition: TrackUnit.cpp:7354
TAllRoutes::TLockedRouteVectorIterator
std::vector< TLockedRouteClass >::iterator TLockedRouteVectorIterator
Definition: TrackUnit.h:1509
TTrack::LCFoundInAutoSigsRoute
bool LCFoundInAutoSigsRoute
true if found an LC during an automatic route search
Definition: TrackUnit.h:648
TPrefDirElement::XLink
int XLink
Definition: TrackUnit.h:214
TAllRoutes::TRouteType
TRouteType
Definition: TrackUnit.h:1499
TRailGraphics::bm133
Graphics::TBitmap * bm133
Definition: GraphicUnit.h:362
TRailGraphics::sm135
Graphics::TBitmap * sm135
Definition: GraphicUnit.h:773
Crossover
@ Crossover
Definition: TrackUnit.h:63
TRailGraphics::bm71green
Graphics::TBitmap * bm71green
Definition: GraphicUnit.h:474
TRailGraphics::bm51
Graphics::TBitmap * bm51
Definition: GraphicUnit.h:445
TTrack::UGME
TUserGraphicMapEntry UGME
an entry for the UserGraphicMap
Definition: TrackUnit.h:709
TRailGraphics::gl21
Graphics::TBitmap * gl21
Definition: GraphicUnit.h:622
TTrack::ElementInLNDone2MultiMap
bool ElementInLNDone2MultiMap(int Caller, int MapPos)
True if the element defined by MapPos is present in LNDone2MultiMap, used during location naming.
Definition: TrackUnit.cpp:7300
TRailGraphics::sm137
Graphics::TBitmap * sm137
Definition: GraphicUnit.h:775
TTrack::IsLCBarrierFlashingAtHV
bool IsLCBarrierFlashingAtHV(int Caller, int HLoc, int VLoc)
True if barrier is in process of opening or closing at H & V.
Definition: TrackUnit.cpp:6226
TTrack::IsPlatformOrNamedNonStationLocationPresent
bool IsPlatformOrNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
True if a non-station named location or platform at HLoc & VLoc.
Definition: TrackUnit.cpp:8415
DefaultTrackLength
#define DefaultTrackLength
Definition: TrackUnit.h:37
TRailGraphics::bm68CallingOn
Graphics::TBitmap * bm68CallingOn
Definition: GraphicUnit.h:451
Signal
@ Signal
Definition: TrackUnit.h:72
TTrack::VLocMin
int VLocMin
Definition: TrackUnit.h:486
TTrack::LevelCrossingAllowed
Set< int, 1, 146 > LevelCrossingAllowed
sets of valid TrackElements for placement of platforms and non-station named locations
Definition: TrackUnit.h:504
TRailGraphics::bm69grounddblwhite
Graphics::TBitmap * bm69grounddblwhite
Definition: GraphicUnit.h:460
TTrack::ContinuationNameMap
std::map< AnsiString, char > ContinuationNameMap
map of all continuation names, char is a dummy
Definition: TrackUnit.h:677
TAllRoutes::GetRouteTypeAndNumber
TRouteType GetRouteTypeAndNumber(int Caller, int TrackVectorPosition, int LinkPos, int &RouteNumber)
Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit)...
Definition: TrackUnit.cpp:15834
TTrackElement::TrainIDOnBridgeTrackPos01
int TrainIDOnBridgeTrackPos01
Definition: TrackUnit.h:150
TTrack::TFixedTrackArray::TFixedTrackArray
TFixedTrackArray()
Array constructor.
Definition: TrackUnit.cpp:1260
TOnePrefDir::CheckOnePrefDir
bool CheckOnePrefDir(int Caller, int NumberOfActiveElements, std::ifstream &VecFile)
Called before PrefDir loading as part of the FileIntegrityCheck function in case there is an error in...
Definition: TrackUnit.cpp:10867
TRailGraphics::bm78Striped
Graphics::TBitmap * bm78Striped
Definition: GraphicUnit.h:505
TTrack::TrainOnLink
bool TrainOnLink(int Caller, int HLoc, int VLoc, int Link, int &TrainID)
New at v1.2.0; checks whether a train present at input location and link and returns its ID if so.
Definition: TrackUnit.cpp:9550
TTrack::ResetAnyNonMatchingGaps
void ResetAnyNonMatchingGaps(int Caller)
Called by EraseTrackElement after the element has been erased and the vector positions changed,...
Definition: TrackUnit.cpp:4157
TTrack::GapPos
int GapPos
Definition: TrackUnit.h:484
TTrack::TrackElementAt
TTrackElement & TrackElementAt(int Caller, int At)
A range-checked version of TrackElement.at(At)
Definition: TrackUnit.cpp:8916
TGraphicElement::Width
int Width
Definition: TrackUnit.h:352
TAllRoutes::RouteLockingRequired
bool RouteLockingRequired(int Caller, int RouteNumber, int RouteTruncatePosition)
Route locking is required (returns true) if a moving train is within 3 signals back from the RouteTru...
Definition: TrackUnit.cpp:16729
TRailGraphics::bmGreenEllipse
Graphics::TBitmap * bmGreenEllipse
Definition: GraphicUnit.h:519
TAllRoutes::GetRouteVectorNumber
int GetRouteVectorNumber(int Caller, IDInt RouteID)
Returns a route's position in AllRoutesVector from its ID, throws an error if a matching route isn't ...
Definition: TrackUnit.cpp:16926
TAllRoutes::GetRouteTypeAndGraphics
TRouteType GetRouteTypeAndGraphics(int Caller, int TrackVectorPosition, int LinkPos, Graphics::TBitmap *&EXGraphicPtr, Graphics::TBitmap *&EntryDirectionGraphicPtr)
Examines Route2MultiMap for the element at TrackVectorPosition with LinkPos (can be entry or exit).
Definition: TrackUnit.cpp:15659
TTrack::ChangingLCVector
TActiveLCVector ChangingLCVector
vector of values for changing level crossings - i.e. barriers in course of being raised or lowered
Definition: TrackUnit.h:682
TRailGraphics::bm73green
Graphics::TBitmap * bm73green
Definition: GraphicUnit.h:487
TTrainController::StopTTClockFlag
bool StopTTClockFlag
when true the timetable clock is stopped, used for messages display and train popup menu display etc
Definition: TrainUnit.h:704
TRailGraphics::gl107
Graphics::TBitmap * gl107
Definition: GraphicUnit.h:569
TRailGraphics::bm53
Graphics::TBitmap * bm53
Definition: GraphicUnit.h:446
TTrack::WriteOperatingTrackToImage
void WriteOperatingTrackToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by TInterface::SaveOperatingImage1Click to add all track element graphics to the image file in...
Definition: TrackUnit.cpp:3717
TUtilities::CheckAndReadFileString
bool CheckAndReadFileString(std::ifstream &InFile, AnsiString &OutString)
checks that the value is a string ('0' or CR accepted as delimiters), returns true for success and re...
Definition: Utilities.cpp:467
TRailGraphics::sm12
Graphics::TBitmap * sm12
Definition: GraphicUnit.h:763
TUserGraphicItem::FileName
AnsiString FileName
Definition: DisplayUnit.h:33
TTrack::TTrackMapIterator
TTrackMap::iterator TTrackMapIterator
Definition: TrackUnit.h:569
TTrack::WriteGraphicsToImage
void WriteGraphicsToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by SaveImageNoGridMenuItemClick, SaveImageAndGridMenuItemClick amd SaveImageAndPrefDirsMenuIte...
Definition: TrackUnit.cpp:3695
TTrack::PlotPastedTrackElementWithAttributes
void PlotPastedTrackElementWithAttributes(int Caller, TTrackElement TempTrackElement, int HLocInput, int VLocInput, bool &TrackLinkingRequiredFlag, bool InternalChecks)
new at v2.2.0 - as PlotAndAddTrackElement but keeping speed & length attributes (for pasting) and als...
Definition: TrackUnit.cpp:2057
TTrack::TLocationNameMultiMapIterator
TLocationNameMultiMap::iterator TLocationNameMultiMapIterator
Definition: TrackUnit.h:604
TRailGraphics::bm70CallingOn
Graphics::TBitmap * bm70CallingOn
Definition: GraphicUnit.h:464
TTrack::RebuildLocationNameMultiMap
void RebuildLocationNameMultiMap(int Caller)
Clears the existing LocationNameMultiMap and rebuilds it from TrackVector and InactiveTrackVector....
Definition: TrackUnit.cpp:7997
TOnePrefDir::EveryPrefDirMarker
void EveryPrefDirMarker(int Caller, TDisplay *Disp)
Similar to PrefDirMarker but used only to mark EveryPrefDir - red for unidirectional PrefDir & green ...
Definition: TrackUnit.cpp:10648
TRailGraphics::gl124
Graphics::TBitmap * gl124
Definition: GraphicUnit.h:588
TRailGraphics::bm32
Graphics::TBitmap * bm32
Definition: GraphicUnit.h:406
TRailGraphics::sm88
Graphics::TBitmap * sm88
Definition: GraphicUnit.h:854
TTrack::SetTrackFinished
void SetTrackFinished(bool Value)
Definition: TrackUnit.h:840
TTrack::GetInactiveTrackElementFromTrackMap
TTrackElement & GetInactiveTrackElementFromTrackMap(int Caller, int HLoc, int VLoc)
Return a reference to the inactive element at HLoc & VLoc, if no element is found an error is thrown.
Definition: TrackUnit.cpp:5108
TAllRoutes::LoadRoutes
bool LoadRoutes(int Caller, std::ifstream &InFile)
Loads the routes from a session file.
Definition: TrackUnit.cpp:17009
TRailGraphics::gl105
Graphics::TBitmap * gl105
Definition: GraphicUnit.h:567
TTrack::PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers
void PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp)
Plot LC elements without any base elements, and set TempMarker true - used in ClearandRebuildRailway.
Definition: TrackUnit.cpp:5836
TOneRoute::StartElement1
TPrefDirElement StartElement1
Definition: TrackUnit.h:1397
TRailGraphics::sm75
Graphics::TBitmap * sm75
Definition: GraphicUnit.h:902
TRailGraphics::sm115
Graphics::TBitmap * sm115
Definition: GraphicUnit.h:761
TOneRoute::ReqPosRouteID
IDInt ReqPosRouteID
session saves as routes in build are not saved in sessions
Definition: TrackUnit.h:1386
TRailGraphics::sm53
Graphics::TBitmap * sm53
Definition: GraphicUnit.h:820
TTrack::PlotRaisedLinkedLevelCrossingBarriers
void PlotRaisedLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp)
Plot & close (to trains) all level crossings linked to TrackElement.
Definition: TrackUnit.cpp:5943
TRailGraphics::bm71CallingOn
Graphics::TBitmap * bm71CallingOn
Definition: GraphicUnit.h:470
TTrack::LCFoundInRouteBuildingFlag
bool LCFoundInRouteBuildingFlag
true if a route set through an LC that is closed to trains (& therefore needs to be opened)
Definition: TrackUnit.h:652
TRailGraphics::DirectionSigRouteGraphicsPtr
Graphics::TBitmap * DirectionSigRouteGraphicsPtr[10]
preferred direction route marker arrows
Definition: GraphicUnit.h:1021
TRailGraphics::DirectionRouteAutoSigsGraphicsPtr
Graphics::TBitmap * DirectionRouteAutoSigsGraphicsPtr[10]
autosigs route marker arrows
Definition: GraphicUnit.h:1023
TRailGraphics::bm93set
Graphics::TBitmap * bm93set
Definition: GraphicUnit.h:513
TTrack::GetTrackVectorPositionFromString
int GetTrackVectorPositionFromString(int Caller, AnsiString String, bool GiveMessages)
Takes the ElementID value (an AnsiString) (e.g. "8-13", "N43-N127", etc) and returns the correspondin...
Definition: TrackUnit.cpp:6654
TOneRoute::TRouteFlash::PlotRouteOriginal
void PlotRouteOriginal(int Caller)
display the original (non route-coloured) graphic
Definition: TrackUnit.cpp:15479
TTrack::TTrackMapEntry
std::pair< THVPair, unsigned int > TTrackMapEntry
Definition: TrackUnit.h:570
TRailGraphics::bm37
Graphics::TBitmap * bm37
Definition: GraphicUnit.h:421
TTrack::ResetLevelCrossings
void ResetLevelCrossings(int Caller)
Set all LC attributes to 0 (closed to trains)
Definition: TrackUnit.cpp:6299
TRailGraphics::sm139
Graphics::TBitmap * sm139
Definition: GraphicUnit.h:777
Erase
@ Erase
Definition: TrackUnit.h:66
TRailGraphics::sm57
Graphics::TBitmap * sm57
Definition: GraphicUnit.h:824
TRailGraphics::bm29
Graphics::TBitmap * bm29
Definition: GraphicUnit.h:397
TRailGraphics::bm72grounddblwhite
Graphics::TBitmap * bm72grounddblwhite
Definition: GraphicUnit.h:479
TTrack::IsTrackLinked
bool IsTrackLinked(int Caller)
True if track has been successfully linked (not used any more)
Definition: TrackUnit.cpp:4788
TTrack::NewVector
TTrackVector NewVector
Definition: TrackUnit.h:705
TAllRoutes::LockedRouteTruncateTrackVectorPosition
unsigned int LockedRouteTruncateTrackVectorPosition
Definition: TrackUnit.h:1548
TUtilities::SaveFileDouble
void SaveFileDouble(std::ofstream &OutFile, double SaveDouble)
converts the double value to a string (if double stored directly it is truncated to 6 digits) then st...
Definition: Utilities.cpp:122
TRailGraphics::sm39
Graphics::TBitmap * sm39
Definition: GraphicUnit.h:804
TRailGraphics::sm85
Graphics::TBitmap * sm85
Definition: GraphicUnit.h:851
TRailGraphics::gl112
Graphics::TBitmap * gl112
Definition: GraphicUnit.h:575
TOnePrefDir::GetExactMatchFrom4MultiMap
TPrefDir4MultiMapIterator GetExactMatchFrom4MultiMap(int Caller, unsigned int PrefDirVectorPosition, bool &FoundFlag)
Retrieves a PrefDir4MultiMap iterator to the PrefDir element at PrefDirVectorPosition....
Definition: TrackUnit.cpp:11473
TTrack::GetAnyElementOppositeLinkPos
int GetAnyElementOppositeLinkPos(int Caller, int TrackVectorPosition, int LinkPos, bool &Derail)
Return the opposite link position for the element at TrackVectorPosition with link position LinkPos,...
Definition: TrackUnit.cpp:9463
Parapet
@ Parapet
Definition: TrackUnit.h:65
TRailGraphics::bm54
Graphics::TBitmap * bm54
Definition: GraphicUnit.h:447
TAllRoutes::GetFixedRouteAt
const TOneRoute & GetFixedRouteAt(int Caller, int At) const
Returns a constant reference to the route at AllRoutesVector position 'At', after performing range ch...
Definition: TrackUnit.cpp:15504
TUtilities::clTransparent
TColor clTransparent
the display background colour, can be white, black or dark blue
Definition: Utilities.h:64
TRailGraphics::sm14
Graphics::TBitmap * sm14
Definition: GraphicUnit.h:778
TRailGraphics::bmStraightEWSignalBlank
Graphics::TBitmap * bmStraightEWSignalBlank
Definition: GraphicUnit.h:985
TPrefDirElement::GetELinkPos
int GetELinkPos() const
Returns the ELink array position.
Definition: TrackUnit.h:276
TTrack::CheckLocationNameMultiMap
void CheckLocationNameMultiMap(int Caller)
Validity test.
Definition: TrackUnit.cpp:7682
TOneRoute::TRouteFlash::PlotRouteOverlay
void PlotRouteOverlay(int Caller)
display the overlay (route-coloured) graphic
Definition: TrackUnit.cpp:15454
TRailGraphics::bm138
Graphics::TBitmap * bm138
Definition: GraphicUnit.h:377
TRailGraphics::sm79striped
Graphics::TBitmap * sm79striped
Definition: GraphicUnit.h:844
TTrack::InactiveTrackVector
TTrackVector InactiveTrackVector
Definition: TrackUnit.h:705
TAllRoutes::DecrementRouteElementNumbersInRoute2MultiMap
void DecrementRouteElementNumbersInRoute2MultiMap(int Caller, int RouteNumber, unsigned int ErasedElementNumber)
After a route element has been erased from the relevant PrefDirVector and from Route2MultiMap,...
Definition: TrackUnit.cpp:16371
TRailGraphics::gl126
Graphics::TBitmap * gl126
Definition: GraphicUnit.h:590
TRailGraphics::sm119
Graphics::TBitmap * sm119
Definition: GraphicUnit.h:907
TTrack::ActiveTrackElementNameMap
TActiveTrackElementNameMap ActiveTrackElementNameMap
map of active track element names
Definition: TrackUnit.h:680
TRailGraphics::sm138
Graphics::TBitmap * sm138
Definition: GraphicUnit.h:776
TTrackElement::HLoc
int HLoc
Definition: TrackUnit.h:144
TRailGraphics::bm72grounddblred
Graphics::TBitmap * bm72grounddblred
Definition: GraphicUnit.h:478
TRailGraphics::sm34
Graphics::TBitmap * sm34
Definition: GraphicUnit.h:799
TDisplay::PlotPointBlank
void PlotPointBlank(int Caller, int HLoc, int VLoc)
Definition: DisplayUnit.cpp:242
TRailGraphics::ConcourseStriped
Graphics::TBitmap * ConcourseStriped
Definition: GraphicUnit.h:549
TRailGraphics::PointModeGraphicsPtr
Graphics::TBitmap * PointModeGraphicsPtr[32][2]
for point fillets - 32 sets of points, each with two fillets
Definition: GraphicUnit.h:1026
TTrack::SigTableTwoAspect
TSigElement SigTableTwoAspect[40]
new at version 0.6 for two aspect
Definition: TrackUnit.h:633
TRailGraphics::sm27
Graphics::TBitmap * sm27
Definition: GraphicUnit.h:791
TTrainController::LogActionError
void LogActionError(int Caller, AnsiString HeadCode, AnsiString OtherHeadCode, TActionEventType ActionEventType, AnsiString LocationID)
Send an error message to the performance log and file, and as a warning if appropriate.
Definition: TrainUnit.cpp:13409
TRailGraphics::sm5
Graphics::TBitmap * sm5
Definition: GraphicUnit.h:816
TPrefDirElement::EXNumber
int EXNumber
used to facilitate identification of the appropriate preferred direction or route graphic
Definition: TrackUnit.h:216
TOnePrefDir::PrefDirMarker
void PrefDirMarker(int Caller, TPrefDirRoute PrefDirRoute, bool BuildingPrefDir, TDisplay *Disp) const
PrefDir and route track marker, including direction markers.
Definition: TrackUnit.cpp:10575
TRailGraphics::bm78
Graphics::TBitmap * bm78
Definition: GraphicUnit.h:504
TTruncateReturnType
TTruncateReturnType
< a flag used during route truncation to indicate the nature of the selected element,...
Definition: TrackUnit.h:1163
TRailGraphics::bm75CallingOn
Graphics::TBitmap * bm75CallingOn
Definition: GraphicUnit.h:496
TRailGraphics::gl130
Graphics::TBitmap * gl130
Definition: GraphicUnit.h:596
TRailGraphics::bm71yellow
Graphics::TBitmap * bm71yellow
Definition: GraphicUnit.h:475
TTrack
Definition: TrackUnit.h:462
TOnePrefDir::SearchLimitHighH
int SearchLimitHighH
Definition: TrackUnit.h:1226
TTrack::TwoAspectBuild
@ TwoAspectBuild
Definition: TrackUnit.h:752
TOnePrefDir::PrefDirVector
TPrefDirVector PrefDirVector
Definition: TrackUnit.h:1233
TAllRoutes::SetTrailingSignalsOnAutoSigsRoute
void SetTrailingSignalsOnAutoSigsRoute(int Caller, int TrackVectorPosition, int XLinkPos)
Enter with signal at TrackVectorElement already set to red by the passing train.
Definition: TrackUnit.cpp:16519
clB5G5R5
#define clB5G5R5
Definition: GraphicUnit.h:286
TUtilities::TimeStamp
AnsiString TimeStamp()
creates a string of the form 'hh:mm:ss' for use in call & event logging
Definition: Utilities.cpp:72
TAllRoutes::TLockedRouteClass::RouteNumber
int RouteNumber
the vector position number of the relevant route in AllRoutesVector
Definition: TrackUnit.h:1486
TTrack::ActiveMapCheck
bool ActiveMapCheck(int Caller, int HLoc, int VLoc, int SpeedTag)
Used to check the validity of footcrossing links.
Definition: TrackUnit.cpp:6929
TRailGraphics::gl2
Graphics::TBitmap * gl2
Definition: GraphicUnit.h:620
TTrack::Tag146Array
int Tag146Array[8][3]
Definition: TrackUnit.h:502
TRailGraphics::sm65
Graphics::TBitmap * sm65
Definition: GraphicUnit.h:833
TRailGraphics::gl47
Graphics::TBitmap * gl47
Definition: GraphicUnit.h:650
TRailGraphics::sm78striped
Graphics::TBitmap * sm78striped
Definition: GraphicUnit.h:842
TTrackElement::ActiveTrackElementName
AnsiString ActiveTrackElementName
Location name used either in the timetable or for a continuation (continuation names not used in time...
Definition: TrackUnit.h:125
TRailGraphics::sm33
Graphics::TBitmap * sm33
Definition: GraphicUnit.h:798
TRailGraphics::bm94set
Graphics::TBitmap * bm94set
Definition: GraphicUnit.h:515
TRailGraphics::gl76Striped
Graphics::TBitmap * gl76Striped
Definition: GraphicUnit.h:685
TPrefDirElement::XLinkPos
int XLinkPos
exit link number & array position
Definition: TrackUnit.h:214
TAllRoutes::StoreOneRouteAfterSessionLoad
void StoreOneRouteAfterSessionLoad(int Caller, TOneRoute *Route)
A new (empty apart from RouteID) TOneRoute is added to the AllRoutesVector after a session load....
Definition: TrackUnit.cpp:16010
TTrack::TActiveLevelCrossing::ConsecSignals
bool ConsecSignals
route type - 0 = nonsignals, 1 = preferred direction (can't have autosigs)
Definition: TrackUnit.h:529
TPrefDirElement::EntryDirectionGraphicPtr
Graphics::TBitmap * EntryDirectionGraphicPtr
pointers to the appropriate entry/exit graphic, or direction marker graphic, for preferred directions...
Definition: TrackUnit.h:222
TTrack::LoadTrack
void LoadTrack(int Caller, std::ifstream &VecFile, bool &GraphicsFollow)
Load track elements (active & inactive) from the file into the relevant vectors and maps,...
Definition: TrackUnit.cpp:2595
TRailGraphics::bm65
Graphics::TBitmap * bm65
Definition: GraphicUnit.h:450
TTrainController::LogEvent
void LogEvent(AnsiString Str)
store Str to the event log - moved from TUtilities for v0.6 so can record the tt clock value
Definition: TrainUnit.cpp:7797
TRailGraphics::sm74
Graphics::TBitmap * sm74
Definition: GraphicUnit.h:901
TTrack::PlotSignalPlatforms
void PlotSignalPlatforms(int Caller, int HLoc, int VLoc, TDisplay *Disp)
Plot platforms if any for a signal graphic - plotted before signal so shows through transparent signa...
Definition: TrackUnit.cpp:5505
TTrack::PlotAndAddTrackElement
void PlotAndAddTrackElement(int Caller, int CurrentTag, int Aspect, int HLocInput, int VLocInput, bool &TrackPlottedFlag, bool InternalChecks)
Called during track building or pasting, when an element identified by CurrentTag (i....
Definition: TrackUnit.cpp:1822
TUtilities::SaveFileString
void SaveFileString(std::ofstream &OutFile, AnsiString SaveString)
stores the string value to the file, then a '0' delimiter then a CR
Definition: Utilities.cpp:130
TTrack::Tag145Array
int Tag145Array[8][3]
Definition: TrackUnit.h:501
TRailGraphics::LCRHSVer
Graphics::TBitmap * LCRHSVer
Definition: GraphicUnit.h:724
TTrackElement::TwoAspect
@ TwoAspect
Definition: TrackUnit.h:155
TRailGraphics::sm76
Graphics::TBitmap * sm76
Definition: GraphicUnit.h:837
TTrack::GapFlashRed
TGraphicElement * GapFlashRed
the red & green circle graphics used to show where the gaps are
Definition: TrackUnit.h:688
TTrack::TryToConnectTrack
bool TryToConnectTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool GiveMessages)
Handles all tasks associated with track linking, returns true if successful (see also LinkTrack & Lin...
Definition: TrackUnit.cpp:2280
TPrefDirElement::ELinkPos
int ELinkPos
entry link number & array position
Definition: TrackUnit.h:212
TAllRoutes::TLockedRouteClass
Handles routes that are locked because of approaching trains.
Definition: TrackUnit.h:1484
TTrack::SetElementID
void SetElementID(int Caller, TTrackElement &TrackElement)
Convert the position values for the TrackElement into an identification string and load in ElementID.
Definition: TrackUnit.cpp:6626
TRailGraphics::bm72yellow
Graphics::TBitmap * bm72yellow
Definition: GraphicUnit.h:481
TOnePrefDir::EndPossible
bool EndPossible(int Caller, bool &LeadingPoints)
Used when setting preferred directions, true if able to finish at the last selected element (can't fi...
Definition: TrackUnit.cpp:10363
TOnePrefDir::ConsolidatePrefDirs
void ConsolidatePrefDirs(int Caller, TOnePrefDir *InputPrefDir)
Used when a preferred direction has been set to add all the elements to EveryPrefDir,...
Definition: TrackUnit.cpp:11120
TTrack::Tag131Array
int Tag131Array[4][3]
Definition: TrackUnit.h:500
TOneRoute::TRouteFlashElement::TrackVectorPosition
int TrackVectorPosition
element values
Definition: TrackUnit.h:1361
TTrack::RetrieveStripedNamedLocationGraphicsWhereRelevant
Graphics::TBitmap * RetrieveStripedNamedLocationGraphicsWhereRelevant(int Caller, TTrackElement TrackElement)
Return a pointer to the striped (i.e. when unnamed) graphic corresponding to TrackElement,...
Definition: TrackUnit.cpp:8853
TTrack::AddName
void AddName(int Caller, TTrackVectorIterator TrackElement, AnsiString Name)
TrackElement.LocationName becomes 'Name' (for active and inactive elements) and, if TrackElement is a...
Definition: TrackUnit.cpp:7263
IDInt
Definition: TrackUnit.h:411
TTrain::GetLeadElement
void GetLeadElement(int Caller)
Called when a train is about to leave an element and move onto another.
Definition: TrainUnit.cpp:2282
TRailGraphics::gl110
Graphics::TBitmap * gl110
Definition: GraphicUnit.h:573
TAllRoutes::GetModifiableRouteAtIDNumber
TOneRoute & GetModifiableRouteAtIDNumber(int Caller, IDInt RouteID)
Returns a modifiable reference to the route with ID number RouteID. If no route is found with that ID...
Definition: TrackUnit.cpp:16977
TRailGraphics::gl130Striped
Graphics::TBitmap * gl130Striped
Definition: GraphicUnit.h:597
TRailGraphics::sm133
Graphics::TBitmap * sm133
Definition: GraphicUnit.h:771
TTrack::FindAndHighlightAnUnsetGap
bool FindAndHighlightAnUnsetGap(int Caller)
True if there is an unset gap, and if so it is marked with a red circle, used during gap setting.
Definition: TrackUnit.cpp:3964
TDisplay
Definition: DisplayUnit.h:48
TTrack::PlotSmallRailway
void PlotSmallRailway(int Caller, TDisplay *Disp)
Plot on screen the zoomed-out railway.
Definition: TrackUnit.cpp:8663
TTrack::LinkTrackNoMessages
bool LinkTrackNoMessages(int Caller, bool FinalCall)
Attempt to link the track and return true if successful, don't issue any screen messages....
Definition: TrackUnit.cpp:4563
TTrackElement::ConnLinkPos
int ConnLinkPos[4]
Connecting element link position (i.e. array positions of the connecting element links,...
Definition: TrackUnit.h:142
TTrainController::ContinuationAutoSigVector
TContinuationAutoSigVector ContinuationAutoSigVector
vector for TContinuationAutoSigEntry objects
Definition: TrainUnit.h:767
TRailGraphics::sm129striped
Graphics::TBitmap * sm129striped
Definition: GraphicUnit.h:765
TRailGraphics::sm48
Graphics::TBitmap * sm48
Definition: GraphicUnit.h:814
TGraphicElement::OverlayGraphic
Graphics::TBitmap * OverlayGraphic
original and temporary overlay graphics
Definition: TrackUnit.h:354
TAllRoutes::CheckForLoopingRoute
bool CheckForLoopingRoute(int Caller, int EndPosition, int EndXLinkPos, int StartPosition)
Functions defined in .cpp file.
Definition: TrackUnit.cpp:17074
TTrack::TTrack
TTrack()
Constructor, only one object of this class.
Definition: TrackUnit.cpp:893
TTrack::FindNamedElementInLocationNameMultiMap
TLocationNameMultiMapIterator FindNamedElementInLocationNameMultiMap(int Caller, AnsiString LocationName, TTrackVectorIterator TrackElement, AnsiString &ErrorString)
Searches LocationNameMultiMap to check if the element pointed to by the TTrackVectorIterator has the ...
Definition: TrackUnit.cpp:7798
TTrackElement::operator==
bool operator==(TTrackElement RHElement)
equivalence operator
Definition: TrackUnit.cpp:120
TTrack::GapHLoc
int GapHLoc
Definition: TrackUnit.h:484
TFixedTrackPiece::Config
TConfiguration Config[4]
the type of link - see TConfiguration above
Definition: TrackUnit.h:94
TTrack::CheckGapMap
void CheckGapMap(int Caller)
Validity test.
Definition: TrackUnit.cpp:6575
NotInRoute
@ NotInRoute
Definition: TrackUnit.h:1164
TDisplay::GetRectangle
void GetRectangle(int Caller, TRect DestRect, TRect SourceRect, Graphics::TBitmap *&OriginalGraphic)
Definition: DisplayUnit.cpp:222
TTrackElement::TrainIDOnElement
int TrainIDOnElement
Definition: TrackUnit.h:150
TRailGraphics::smRed
Graphics::TBitmap * smRed
Definition: GraphicUnit.h:878
TTrack::FlipArray
int FlipArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'flipping' via menu items 'Edit' & 'Flip'
Definition: TrackUnit.h:666
TRailGraphics::bm139
Graphics::TBitmap * bm139
Definition: GraphicUnit.h:380
TRailGraphics::gl3
Graphics::TBitmap * gl3
Definition: GraphicUnit.h:631
TPrefDirElement::CheckCount
int CheckCount
internal check value used when building preferred directions
Definition: TrackUnit.h:220
TRailGraphics::bm20
Graphics::TBitmap * bm20
Definition: GraphicUnit.h:392
TRailGraphics::sm77striped
Graphics::TBitmap * sm77striped
Definition: GraphicUnit.h:840
TAllRoutes::RebuildRailwayFlag
bool RebuildRailwayFlag
this is set whenever a route has to be cancelled forcibly in order to force a ClearandRebuildRailway ...
Definition: TrackUnit.h:1553
TUtilities::LoadFileInt
int LoadFileInt(std::ifstream &InFile)
loads an int value from the file
Definition: Utilities.cpp:153
TTrack::SignalAspectBuildMode
enum TTrack::@2 SignalAspectBuildMode
aspect mode for future signal additions
TTrackElement::ElementID
AnsiString ElementID
the element identifier based on position in the railway
Definition: TrackUnit.h:127
TRailGraphics::sm112
Graphics::TBitmap * sm112
Definition: GraphicUnit.h:760
TTrack::CheckMapAndInactiveTrack
void CheckMapAndInactiveTrack(int Caller)
Validity test.
Definition: TrackUnit.cpp:6543
TTrack::TActiveLevelCrossing::StartTime
TDateTime StartTime
stores the starting time for level crossing changing
Definition: TrackUnit.h:543
TRailGraphics::sm36
Graphics::TBitmap * sm36
Definition: GraphicUnit.h:801
TRailGraphics::sm136
Graphics::TBitmap * sm136
Definition: GraphicUnit.h:774
TRailGraphics::gl98
Graphics::TBitmap * gl98
Definition: GraphicUnit.h:715
TTrackElement::VLoc
int VLoc
The h & v locations in the railway (top lh corner of the first build screen = 0,0)
Definition: TrackUnit.h:144
TTrack::GetNonPointsOppositeLinkPos
int GetNonPointsOppositeLinkPos(int LinkPosIn)
Return the corresponding link position (track always occupies either links 0 & 1 or 2 & 3)
Definition: TrackUnit.h:786
TRailGraphics::sm100
Graphics::TBitmap * sm100
Definition: GraphicUnit.h:747
TOneRoute::TRouteFlash::RouteFlashVector
std::vector< TRouteFlashElement > RouteFlashVector
Definition: TrackUnit.h:1372
TRailGraphics::sm63
Graphics::TBitmap * sm63
Definition: GraphicUnit.h:831
TAllRoutes::TLockedRouteClass::LastTrackVectorPosition
unsigned int LastTrackVectorPosition
the TrackVector position of the last (i.e. most forward) element in the route
Definition: TrackUnit.h:1490
TRailGraphics::sm60
Graphics::TBitmap * sm60
Definition: GraphicUnit.h:828
TAllRoutes::NoRoute
@ NoRoute
Definition: TrackUnit.h:1500
TRailGraphics::bm42
Graphics::TBitmap * bm42
Definition: GraphicUnit.h:436
TTrack::RepositionAndMapTrack
bool RepositionAndMapTrack(int Caller)
When track is being built it is entered into the TrackVector in the order in which it is built,...
Definition: TrackUnit.cpp:4228
TRailGraphics::gl108
Graphics::TBitmap * gl108
Definition: GraphicUnit.h:570
TTrack::AdjNamedElement
bool AdjNamedElement(int Caller, int HLoc, int VLoc, int SpeedTag, AnsiString &LocationName, int &FoundElement)
Definition: TrackUnit.cpp:7621
TTrainController::RestartTime
TDateTime RestartTime
TTClockTime when operation pauses ( = timetable start time prior to operation) TTClockTime is calcula...
Definition: TrainUnit.h:637
TOneRoute::ConvertAndAddPreferredRouteSearchVector
void ConvertAndAddPreferredRouteSearchVector(int Caller, IDInt ReqPosRouteID, bool AutoSigsFlag)
Called after a preferred (i.e. preferred direction or automatic signals) route has been selected and ...
Definition: TrackUnit.cpp:13475
TOnePrefDir::ClearPrefDir
void ClearPrefDir()
Empty the existing vectors & map.
Definition: TrackUnit.h:1191
TRailGraphics::gl99
Graphics::TBitmap * gl99
Definition: GraphicUnit.h:716
TGraphicElement::OverlayLoaded
bool OverlayLoaded
Definition: TrackUnit.h:348
TOnePrefDir::RealignAfterTrackErase
void RealignAfterTrackErase(int Caller, int ErasedTrackVectorPosition)
After a track element is erased the preferred direction elements are likely to be affected....
Definition: TrackUnit.cpp:11579
TRailGraphics::sm4
Graphics::TBitmap * sm4
Definition: GraphicUnit.h:805
PrefDirCall
@ PrefDirCall
Definition: TrackUnit.h:1170
TTrackElement::StationEntryStopLinkPos1
int StationEntryStopLinkPos1
Definition: TrackUnit.h:148
Points
@ Points
Definition: TrackUnit.h:63
TRailGraphics::gl89unset
Graphics::TBitmap * gl89unset
Definition: GraphicUnit.h:702
TOneRoute::SearchForPreferredRoute
bool SearchForPreferredRoute(int Caller, TPrefDirElement PrefDirElement, int XLinkPos, int RequiredPosition, IDInt ReqPosRouteID, TOnePrefDir *EveryPrefDir, bool ConsecSignalsRoute, int EndSelectPosition, bool AutoSigsFlag)
Called by GetNextPreferredRouteElement to carry out the search for a valid route, and also called rec...
Definition: TrackUnit.cpp:12990
TRailGraphics::LCPlain
Graphics::TBitmap * LCPlain
Definition: GraphicUnit.h:723
TAllRoutes::FindRoutePairFromRoute2MultiMap
TRouteElementPair FindRoutePairFromRoute2MultiMap(int Caller, int HLoc, int VLoc, int ELink, TRoute2MultiMapIterator &Route2MultiMapIterator)
Examines Route2MultiMap and returns a TRouteElementPair if one is found with the passed values of H,...
Definition: TrackUnit.cpp:16084
TRailGraphics::sm80
Graphics::TBitmap * sm80
Definition: GraphicUnit.h:846
TTrack::IsElementDefaultLength
bool IsElementDefaultLength(int Caller, TTrackElement &TrackElement, bool FirstTrack, bool &LengthDifferent, bool &SpeedDifferent)
Definition: TrackUnit.cpp:8346
TTrack::PopulateLCVector
void PopulateLCVector(int Caller)
Add all LCs to LCVector - note that this contains all LC elements whether linked to others or not.
Definition: TrackUnit.cpp:9533
TRailGraphics::bm33
Graphics::TBitmap * bm33
Definition: GraphicUnit.h:409
TRailGraphics::gl119
Graphics::TBitmap * gl119
Definition: GraphicUnit.h:582
TRailGraphics::sm47
Graphics::TBitmap * sm47
Definition: GraphicUnit.h:813
TRailGraphics::bm75grounddblred
Graphics::TBitmap * bm75grounddblred
Definition: GraphicUnit.h:498
Trail
@ Trail
Definition: TrackUnit.h:72
TTrack::ChangeLocationNameMultiMapEntry
void ChangeLocationNameMultiMapEntry(int Caller, AnsiString NewName, TLocationNameMultiMapIterator SNIterator)
Changes the LocationName in the name multimap to NewName at the location pointed to by the TLocationN...
Definition: TrackUnit.cpp:7855
TOneRoute::SetRearwardsSignalsReturnFalseForTrain
bool SetRearwardsSignalsReturnFalseForTrain(int Caller, int &Attribute, int PrefDirVectorStartPosition) const
Called by TAllRoutes::SetAllRearwardsSignals to set rearwards signals from a specified starting posit...
Definition: TrackUnit.cpp:14989
TRailGraphics::sm107
Graphics::TBitmap * sm107
Definition: GraphicUnit.h:754
TGraphicElement::LoadOverlayGraphic
void LoadOverlayGraphic(int Caller, Graphics::TBitmap *Overlay)
Load the temporary overlay graphic.
Definition: TrackUnit.cpp:1568
TRailGraphics::bm75dblyellow
Graphics::TBitmap * bm75dblyellow
Definition: GraphicUnit.h:497
FailLockedRoute
@ FailLockedRoute
Definition: TrainUnit.h:40
TRailGraphics::sm32
Graphics::TBitmap * sm32
Definition: GraphicUnit.h:797
TOneRoute::SetRouteSignals
void SetRouteSignals(int Caller) const
Called when setting a route to set all points appropriately. Also called when a new train is added at...
Definition: TrackUnit.cpp:14814
TRailGraphics::sm44
Graphics::TBitmap * sm44
Definition: GraphicUnit.h:810
TRailGraphics::gl44
Graphics::TBitmap * gl44
Definition: GraphicUnit.h:647
TRailGraphics::bm36
Graphics::TBitmap * bm36
Definition: GraphicUnit.h:418
TRailGraphics::LCTopHor
Graphics::TBitmap * LCTopHor
Definition: GraphicUnit.h:725
Continuation
@ Continuation
Definition: TrackUnit.h:63
TRailGraphics::DirectionPrefDirGraphicsPtr
Graphics::TBitmap * DirectionPrefDirGraphicsPtr[10]
preferred direction marker arrows
Definition: GraphicUnit.h:1017
TUserGraphicItem::Height
int Height
Definition: DisplayUnit.h:35
TTrack::GetFilletGraphic
Graphics::TBitmap * GetFilletGraphic(int Caller, TTrackElement TrackElement)
Return a pointer to the point fillet (the bit that appears to move when points are changed) for the p...
Definition: TrackUnit.cpp:6422
GraphicUnit.h
THVPair
std::pair< int, int > THVPair
HLoc/VLoc position pair.
Definition: InterfaceUnit.h:46
TTrack::RebuildTrackAndText
void RebuildTrackAndText(int Caller, TDisplay *Disp, bool BothPointFilletsAndBasicLCs)
Called by TInterface::ClearandRebuildRailway to replot all the active and inactive track elements and...
Definition: TrackUnit.cpp:3325
TextUnit.h
TTrack::PlotPoints
void PlotPoints(int Caller, TTrackElement TrackElement, TDisplay *Disp, bool BothFillets)
Plot points on screen according to how they are set (Attribute value), or, with both fillets if BothF...
Definition: TrackUnit.cpp:5344
TDisplay::DisplayZoomOutOffsetV
static int DisplayZoomOutOffsetV
the verticalal offset of the zoomed-out display
Definition: DisplayUnit.h:86
TTrack::RightPlatAllowed
Set< int, 1, 146 > RightPlatAllowed
Definition: TrackUnit.h:504
TRailGraphics::bm12
Graphics::TBitmap * bm12
Definition: GraphicUnit.h:355
TTrack::DecrementValuesInInactiveTrackAndNameMaps
void DecrementValuesInInactiveTrackAndNameMaps(int Caller, unsigned int VecPos)
After an element has been erased from the InactiveTrackVector, all the later elements are moved down ...
Definition: TrackUnit.cpp:7902
TRailGraphics::sm8
Graphics::TBitmap * sm8
Definition: GraphicUnit.h:845
TRailGraphics::sm87
Graphics::TBitmap * sm87
Definition: GraphicUnit.h:853
AllRoutes
TAllRoutes * AllRoutes
the object pointer, object created in InterfaceUnit
Definition: TrackUnit.cpp:53
TRailGraphics::sm94
Graphics::TBitmap * sm94
Definition: GraphicUnit.h:861
TOnePrefDir::ValidatePrefDir
bool ValidatePrefDir(int Caller)
Checks that all elements in PrefDirVector have been properly set, i.e. don't have their default value...
Definition: TrackUnit.cpp:10406
TTrack::LinkHVArray
int LinkHVArray[10][2]
array used to determine relative horizontal & vertical track element positions for specific link valu...
Definition: TrackUnit.h:490
TRailGraphics::sm49
Graphics::TBitmap * sm49
Definition: GraphicUnit.h:815
TTextHandler::TextErase
bool TextErase(int Caller, int HPosition, int VPosition)
look for a text item in the vicinity of HPosInput & VPosInput & erase it if found
Definition: TextUnit.cpp:249
TRailGraphics::sm1
Graphics::TBitmap * sm1
Definition: GraphicUnit.h:745
TRailGraphics::sm84
Graphics::TBitmap * sm84
Definition: GraphicUnit.h:850
TGraphicElement::ScreenGraphicLoaded
bool ScreenGraphicLoaded
Definition: TrackUnit.h:348
TTrack::PlotLCBaseElementsOnly
void PlotLCBaseElementsOnly(int Caller, TBarrierState State, int BaseElementSpeedTag, int HLoc, int VLoc, bool ConsecSignals, TDisplay *Disp)
Just replot the basic track elements at a level crossing (for flashing)
Definition: TrackUnit.cpp:6090
TTrack::TopPlatAllowed
Set< int, 1, 146 > TopPlatAllowed
Definition: TrackUnit.h:504
TRailGraphics::LinkPrefDirGraphicsPtr
Graphics::TBitmap * LinkPrefDirGraphicsPtr[30]
preferred direction graphic overlay
Definition: GraphicUnit.h:1006
TTrack::CheckTrackElementsInFile
bool CheckTrackElementsInFile(int Caller, int &NumberOfActiveElements, bool &GraphicsFollow, std::ifstream &VecFile)
True if TrackElements in the file are all valid.
Definition: TrackUnit.cpp:2961
TGraphicElement::Height
int Height
dimensions in pixels
Definition: TrackUnit.h:352
TRailGraphics::sm98
Graphics::TBitmap * sm98
Definition: GraphicUnit.h:866
TOneRoute::StartSelectionRouteID
IDInt StartSelectionRouteID
needed for session saves as routes in build are not saved in sessions
Definition: TrackUnit.h:1389
TFixedTrackPiece::SpeedTag
int SpeedTag
The element identification number - corresponds to the relevant SpeedButton->Tag.
Definition: TrackUnit.h:84
TRailGraphics::bm68green
Graphics::TBitmap * bm68green
Definition: GraphicUnit.h:455
TRailGraphics::gl79
Graphics::TBitmap * gl79
Definition: GraphicUnit.h:688
TTrain::Stopped
bool Stopped()
True if the train has stopped for any reason.
Definition: TrainUnit.h:607
TTrack::SigTableGroundSignal
TSigElement SigTableGroundSignal[40]
new at version 0.6 for ground signals
Definition: TrackUnit.h:635
TAllRoutes::LockedRouteLastXLinkPos
int LockedRouteLastXLinkPos
Definition: TrackUnit.h:1547
TRailGraphics::sm113
Graphics::TBitmap * sm113
Definition: GraphicUnit.h:903
TRailGraphics::bm135
Graphics::TBitmap * bm135
Definition: GraphicUnit.h:368
TPrefDirElement::GetELink
int GetELink() const
Returns ELink.
Definition: TrackUnit.h:270
TUtilities::CheckFileDouble
bool CheckFileDouble(std::ifstream &InFile)
checks that the value is a double, returns true for success
Definition: Utilities.cpp:293
TRailGraphics::sm61
Graphics::TBitmap * sm61
Definition: GraphicUnit.h:829
TAllRoutes::DiagonalFouledByRouteOrTrain
bool DiagonalFouledByRouteOrTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber)
The track geometry allows diagonals to cross without occupying the same track element,...
Definition: TrackUnit.cpp:17132
TRailGraphics::bm73grounddblwhite
Graphics::TBitmap * bm73grounddblwhite
Definition: GraphicUnit.h:486
TOnePrefDir::CheckPrefDir4MultiMap
void CheckPrefDir4MultiMap(int Caller)
Diagnostic validity check.
Definition: TrackUnit.cpp:11306
TRailGraphics::BridgeSigRouteGraphicsPtr
Graphics::TBitmap * BridgeSigRouteGraphicsPtr[12]
route graphic for preferred routes overlay
Definition: GraphicUnit.h:995
TRailGraphics::bm73dblyellow
Graphics::TBitmap * bm73dblyellow
Definition: GraphicUnit.h:484
TRailGraphics::sm111
Graphics::TBitmap * sm111
Definition: GraphicUnit.h:759
TOneRoute::TRouteFlashElement::OriginalGraphic
Graphics::TBitmap * OriginalGraphic
Definition: TrackUnit.h:1363
TRailGraphics::BridgeRouteAutoSigsGraphicsPtr
Graphics::TBitmap * BridgeRouteAutoSigsGraphicsPtr[12]
route graphic for automatic signal routes overlay
Definition: GraphicUnit.h:999
TDisplay::DisplayZoomOutOffsetH
static int DisplayZoomOutOffsetH
the horizontal offset of the zoomed-out display
Definition: DisplayUnit.h:84
Display
TDisplay * Display
The object pointer for the on-screen display, object created in InterfaceUnit.
Definition: DisplayUnit.cpp:54
TRailGraphics::bm106
Graphics::TBitmap * bm106
Definition: GraphicUnit.h:349
TRailGraphics::bm56
Graphics::TBitmap * bm56
Definition: GraphicUnit.h:448
TTrack::RotRightArray
int RotRightArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'rotating right' via menu items 'Edit' & 'Rotate right'
Definition: TrackUnit.h:672
TRailGraphics::gl146Striped
Graphics::TBitmap * gl146Striped
Definition: GraphicUnit.h:615
TTrack::GetVLocMin
int GetVLocMin()
Definition: TrackUnit.h:780
TTrack::ResetPoints
void ResetPoints(int Caller)
Called on exit from operation to reset all points to non-diverging or to left fork (Attribute = 0)
Definition: TrackUnit.cpp:4213
TRailGraphics::sm96striped
Graphics::TBitmap * sm96striped
Definition: GraphicUnit.h:864
TAllRoutes::StoreOneRoute
void StoreOneRoute(int Caller, TOneRoute *Route)
A new (empty apart from RouteID) TOneRoute is added to the AllRoutesVector.
Definition: TrackUnit.cpp:15981
TAllRoutes::AllRoutesSize
unsigned int AllRoutesSize() const
Returns the number of routes in the railway.
Definition: TrackUnit.h:1580
TRailGraphics::gl87
Graphics::TBitmap * gl87
Definition: GraphicUnit.h:698
TDisplay::Ellipse
void Ellipse(int Caller, int HPos, int VPos, TColor Col)
Plot an ellipse at the defined position and with the defined colour.
Definition: DisplayUnit.cpp:122
TRailGraphics::gl113
Graphics::TBitmap * gl113
Definition: GraphicUnit.h:576
TTrack::LCVector
TLCVector LCVector
vector of level crossing InactiveTrackVector positions
Definition: TrackUnit.h:692
TRailGraphics::gl49
Graphics::TBitmap * gl49
Definition: GraphicUnit.h:652
TUtilities::CheckFileBool
bool CheckFileBool(std::ifstream &InFile)
checks that the value is a bool returns true for success
Definition: Utilities.cpp:197
TTrack::OtherTrainOnTrack
bool OtherTrainOnTrack(int Caller, int NextPos, int NextEntryPos, int OwnTrainID)
True if another train on NextEntryPos track of element at NextPos, whether bridge or not,...
Definition: TrackUnit.cpp:9327
TRailGraphics::sm38
Graphics::TBitmap * sm38
Definition: GraphicUnit.h:803
TTrack::TActiveTrackElementNameMapEntry
std::pair< AnsiString, int > TActiveTrackElementNameMapEntry
Definition: TrackUnit.h:616
TOnePrefDir::SearchLimitHighV
int SearchLimitHighV
Definition: TrackUnit.h:1228
TAllRoutes::SaveRoutes
void SaveRoutes(int Caller, std::ofstream &OutFile)
Save railway route information to a session file or an error file.
Definition: TrackUnit.cpp:16993
TTrack::Tag77Array
int Tag77Array[25][3]
Definition: TrackUnit.h:494
TGraphicElement::PlotOverlay
void PlotOverlay(int Caller, TDisplay *Disp)
Plot the overlay graphic on screen.
Definition: TrackUnit.cpp:1578
TTrack::ResetSignals
void ResetSignals(int Caller)
Called on exit from operation to reset all signals to red (Attribute = 0)
Definition: TrackUnit.cpp:4198
Connection
@ Connection
Definition: TrackUnit.h:72
TTrack::LoadBarriersDownVector
void LoadBarriersDownVector(int Caller, std::ifstream &VecFile)
Load all BarriersDownVector values from SessionFile.
Definition: TrackUnit.cpp:3302
TPrefDirElement::ConsecSignals
bool ConsecSignals
marker within the route for ConsecSignalsRoute element
Definition: TrackUnit.h:255
TRailGraphics::bm13
Graphics::TBitmap * bm13
Definition: GraphicUnit.h:358
TAllRoutes::RouteTruncateFlag
bool RouteTruncateFlag
used to flag the fact that a route is being truncated on order to change the behaviour of signal aspe...
Definition: TrackUnit.h:1555
TTrack::MarkOneLength
void MarkOneLength(int Caller, TTrackElement TE, bool FirstTrack, TDisplay *Disp)
Mark on screen a track element according to its length and speed limit if either of these differ from...
Definition: TrackUnit.cpp:8114
TRailGraphics::bmStraightNSSignalBlank
Graphics::TBitmap * bmStraightNSSignalBlank
Definition: GraphicUnit.h:986
TRailGraphics::bm75green
Graphics::TBitmap * bm75green
Definition: GraphicUnit.h:500
TOneRoute::ConvertAndAddNonPreferredRouteSearchVector
void ConvertAndAddNonPreferredRouteSearchVector(int Caller, IDInt ReqPosRouteID)
Called after a non-preferred (i.e. unrestricted) route has been selected and has finished flashing,...
Definition: TrackUnit.cpp:14624
TOnePrefDir::ConvertPrefDirSearchVector
void ConvertPrefDirSearchVector(int Caller)
Called after a successful search to add the elements from the search vector to the pref dir vector.
Definition: TrackUnit.cpp:10237
TRailGraphics::gl91set
Graphics::TBitmap * gl91set
Definition: GraphicUnit.h:706
TRailGraphics::sm37
Graphics::TBitmap * sm37
Definition: GraphicUnit.h:802
TTrack::ElementInLNPendingList
bool ElementInLNPendingList(int Caller, int MapPos)
Definition: TrackUnit.cpp:7327
TRailGraphics::sm86
Graphics::TBitmap * sm86
Definition: GraphicUnit.h:852
TRailGraphics::LinkGraphicsPtr
Graphics::TBitmap * LinkGraphicsPtr[30]
basic single track graphic for use in plotting the original graphic during route flashing
Definition: GraphicUnit.h:1004
TAllRoutes::CheckMapAndRoutes
void CheckMapAndRoutes(int Caller)
Diagnostic function - checks equivalence for each route between entries in PrefDirVector and those in...
Definition: TrackUnit.cpp:16295
TAllRoutes::GetRouteElementDataFromRoute2MultiMap
TRouteElementPair GetRouteElementDataFromRoute2MultiMap(int Caller, int HLoc, int VLoc, TRouteElementPair &SecondPair)
Retrieve up to two TRouteElementPair entries from Route2MultiMap at H & V, the first as a function re...
Definition: TrackUnit.cpp:16251
DefaultTrackSpeedLimit
#define DefaultTrackSpeedLimit
Definition: TrackUnit.h:38
TTrack::PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers
void PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp)
Plot LC elements without any base elements, and set TempMarker true - used in ClearandRebuildRailway.
Definition: TrackUnit.cpp:6016
TPrefDirElement::GetPrefDirGraphicPtr
Graphics::TBitmap * GetPrefDirGraphicPtr()
picks up the EXGraphicPtr for preferred directions
Definition: TrackUnit.cpp:459
TTrack::PlatformOnSignalSide
bool PlatformOnSignalSide(int Caller, int HLoc, int VLoc, int SpeedTag, Graphics::TBitmap *&SignalPlatformGraphic)
Check whether there is a platform present at HLoc & VLoc at the same side as the signal represented b...
Definition: TrackUnit.cpp:9214
TRailGraphics::gl80
Graphics::TBitmap * gl80
Definition: GraphicUnit.h:691
TRailGraphics::sm79
Graphics::TBitmap * sm79
Definition: GraphicUnit.h:843
TTrack::SigTable
TSigElement SigTable[40]
original table of signals for four aspect
Definition: TrackUnit.h:629
TOnePrefDir::TPrefDirVectorConstIterator
std::vector< TPrefDirElement >::const_iterator TPrefDirVectorConstIterator
Definition: TrackUnit.h:1216
TRailGraphics::smName
Graphics::TBitmap * smName
Definition: GraphicUnit.h:875
TRailGraphics::bm73grounddblred
Graphics::TBitmap * bm73grounddblred
Definition: GraphicUnit.h:485
TTrack::InactiveTrackElementPresentAtHV
bool InactiveTrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
New at v1.2.0; true if an inactive track element present.
Definition: TrackUnit.cpp:5152
TRailGraphics::sm7
Graphics::TBitmap * sm7
Definition: GraphicUnit.h:836
TRailGraphics::gl91unset
Graphics::TBitmap * gl91unset
Definition: GraphicUnit.h:707
TRailGraphics::bm50
Graphics::TBitmap * bm50
Definition: GraphicUnit.h:444
TDisplay::PlotSignalBlank
void PlotSignalBlank(int Caller, int HLoc, int VLoc, int SpeedTag, bool RHSFlag)
Definition: DisplayUnit.cpp:255
TGraphicElement::OriginalLoaded
bool OriginalLoaded
Definition: TrackUnit.h:348
TTrack::SetStationEntryStopLinkPosses
void SetStationEntryStopLinkPosses(int Caller)
Called when trying to link track and when a name changed when track already linked.
Definition: TrackUnit.cpp:8469
TTrack::HLocMin
int HLocMin
Definition: TrackUnit.h:486
TTrack::SigTableThreeAspect
TSigElement SigTableThreeAspect[40]
new at version 0.6 for three aspect
Definition: TrackUnit.h:631
TTrack::CopyFlag
bool CopyFlag
true only when copying a selection, used to prevent location names being copied
Definition: TrackUnit.h:642
TAllRoutes::GetModifiableRouteAt
TOneRoute & GetModifiableRouteAt(int Caller, int At)
Returns a modifiable reference to the route at AllRoutesVector position 'At', after performing range ...
Definition: TrackUnit.cpp:15518
TTrack::LinkTrack
bool LinkTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool FinalCall)
Attempt to link the track and return true if successful, if unsuccessful return error flag and positi...
Definition: TrackUnit.cpp:4338
TRailGraphics::sm16
Graphics::TBitmap * sm16
Definition: GraphicUnit.h:780
TTrack::ErrorInTrackBeforeSetGaps
bool ErrorInTrackBeforeSetGaps(int Caller, int &HLoc, int &VLoc)
Check for track errors prior to gap setting - disused as incorporated a time-consuming double brute f...
Definition: TrackUnit.cpp:2383
TRailGraphics::gl69
Graphics::TBitmap * gl69
Definition: GraphicUnit.h:674
TTrack::CheckMapAndTrack
void CheckMapAndTrack(int Caller)
Validity test.
Definition: TrackUnit.cpp:6503
TRailGraphics::bm140
Graphics::TBitmap * bm140
Definition: GraphicUnit.h:386
TTrack::LoadGraphics
void LoadGraphics(int Caller, std::ifstream &VecFile, UnicodeString GraphicsPath)
new at v2.4.0, load user graphics
Definition: TrackUnit.cpp:2723
TRailGraphics::bm137
Graphics::TBitmap * bm137
Definition: GraphicUnit.h:374
TRailGraphics::sm64
Graphics::TBitmap * sm64
Definition: GraphicUnit.h:832
TTrackElement::LocationName
AnsiString LocationName
location name not used for timetabling, only for identification: platforms, non-station named locatio...
Definition: TrackUnit.h:129
TRailGraphics::sm90
Graphics::TBitmap * sm90
Definition: GraphicUnit.h:857
TRailGraphics::bm136
Graphics::TBitmap * bm136
Definition: GraphicUnit.h:371
TOneRoute::SetRoutePoints
void SetRoutePoints(int Caller) const
Called when setting a route to set all points appropriately.
Definition: TrackUnit.cpp:14785
TTrack::TActiveLevelCrossing::HLoc
int HLoc
HLoc value for found level crossing element.
Definition: TrackUnit.h:539
TDisplay::DisplayOffsetH
static int DisplayOffsetH
the horizontal offset of the displayed screen
Definition: DisplayUnit.h:76
TOnePrefDir::PresetAutoRouteElementValid
bool PresetAutoRouteElementValid(int Caller, TPrefDirElement ElementIn, int EntryPos)
Checks ElementIn and returns true only if a single prefdir set at that H&V, with EntryPos giving entr...
Definition: TrackUnit.cpp:11831
TPrefDirElement::EntryExitNumber
bool EntryExitNumber()
determines and loads EXNumber (see above)
Definition: TrackUnit.cpp:264
TRailGraphics::bm101
Graphics::TBitmap * bm101
Definition: GraphicUnit.h:348
TTrack::SkipLocationNameMultiMapCheck
bool SkipLocationNameMultiMapCheck
changed from PastingWithAttributes in v2.4.0 as all pastes are now with attributes - needed to suppre...
Definition: TrackUnit.h:658
TRailGraphics::gl125
Graphics::TBitmap * gl125
Definition: GraphicUnit.h:589
TTrack::TLocationNameMultiMapRange
std::pair< TLocationNameMultiMapIterator, TLocationNameMultiMapIterator > TLocationNameMultiMapRange
Definition: TrackUnit.h:605
TRailGraphics::gl145Striped
Graphics::TBitmap * gl145Striped
Definition: GraphicUnit.h:613
TRailGraphics::bm27
Graphics::TBitmap * bm27
Definition: GraphicUnit.h:393
TRailGraphics::bm73yellow
Graphics::TBitmap * bm73yellow
Definition: GraphicUnit.h:488
InRouteTrue
@ InRouteTrue
Definition: TrackUnit.h:1164
TTrack::TUserGraphicMapEntry
std::pair< AnsiString, TPicture * > TUserGraphicMapEntry
an entry for TUserGraphicMap
Definition: TrackUnit.h:564
TRailGraphics::bm69yellow
Graphics::TBitmap * bm69yellow
Definition: GraphicUnit.h:462
TTrack::TGapMapIterator
TGapMap::iterator TGapMapIterator
the first gap HLoc/VLoc pair, contains one entry for each pair of matched gaps
Definition: TrackUnit.h:574
TRailGraphics::bmTransparentBgnd
Graphics::TBitmap * bmTransparentBgnd
Definition: GraphicUnit.h:891
TRailGraphics::gl23
Graphics::TBitmap * gl23
Definition: GraphicUnit.h:624
TOnePrefDir::GetNextPrefDirElement
bool GetNextPrefDirElement(int Caller, int HLoc, int VLoc, bool &FinishElement)
Used when continuing a chain of preferred directions or element lengths. Tries to find a set of linke...
Definition: TrackUnit.cpp:9817
TRailGraphics::bm68grounddblwhite
Graphics::TBitmap * bm68grounddblwhite
Definition: GraphicUnit.h:454
TGraphicElement::OverlayPlotted
bool OverlayPlotted
Definition: TrackUnit.h:348
TRailGraphics::bm93unset
Graphics::TBitmap * bm93unset
Definition: GraphicUnit.h:514
TRailGraphics::sm122
Graphics::TBitmap * sm122
Definition: GraphicUnit.h:910
TFixedTrackPiece::TrackType
TTrackType TrackType
the type of track element
Definition: TrackUnit.h:97
TPrefDirElement::GetDirectionRouteGraphicPtr
Graphics::TBitmap * GetDirectionRouteGraphicPtr(bool AutoSigsFlag, bool ConsecSignalsRoute) const
picks up the green or red route direction graphic
Definition: TrackUnit.cpp:827
TOneRoute::TRouteFlashElement
A single flashing element of a route that flashes during setting.
Definition: TrackUnit.h:1359
TPrefDirElement
Basic preferred direction or route element - track element with additional members.
Definition: TrackUnit.h:209
TRailGraphics::sm26
Graphics::TBitmap * sm26
Definition: GraphicUnit.h:790
TGraphicElement::~TGraphicElement
~TGraphicElement()
Destructor.
Definition: TrackUnit.cpp:1476
TTrack::SearchForAndUpdateLocationName
void SearchForAndUpdateLocationName(int Caller, int HLoc, int VLoc, int SpeedTag)
Checks all locations that are adjacent to the one entered for linked named location elements.
Definition: TrackUnit.cpp:7479
TRailGraphics::gl24
Graphics::TBitmap * gl24
Definition: GraphicUnit.h:625
TRailGraphics::gl109
Graphics::TBitmap * gl109
Definition: GraphicUnit.h:571
TTrack::TSigElement
Used as basic elements in a table of signals - see SigTable below.
Definition: TrackUnit.h:620
TOnePrefDir::GetOnePrefDirPosition
int GetOnePrefDirPosition(int Caller, int HLoc, int VLoc)
Although there may be up to four entries at one H & V position this function gets just one....
Definition: TrackUnit.cpp:11550
TAllRoutes::GetFixedRouteAtIDNumber
const TOneRoute & GetFixedRouteAtIDNumber(int Caller, IDInt RouteID) const
Returns a constant reference to the route with ID number RouteID. If no route is found with that ID a...
Definition: TrackUnit.cpp:16961
TTrackElement::Attribute
int Attribute
special variable used only for points, signals & level crossings, ignored otherwise points: 0=set to ...
Definition: TrackUnit.h:138
TTrack::TBarrierState
TBarrierState
< state of barriers
Definition: TrackUnit.h:521
TOnePrefDir::SearchLimitLowH
int SearchLimitLowH
Definition: TrackUnit.h:1225
TRailGraphics::SetUpAllDerivitiveGraphics
void SetUpAllDerivitiveGraphics(TColor TransparentColour)
Definition: GraphicUnit.cpp:4093
TTrack::LocationNameMultiMap
TLocationNameMultiMap LocationNameMultiMap
multimap of location names (see type for more information above)
Definition: TrackUnit.h:698
TTrack::NoNamedLocationElements
bool NoNamedLocationElements(int Caller)
True if there are no NamedLocationElements (includes footcrossings)
Definition: TrackUnit.cpp:4090
TTrack::EraseTrackElement
void EraseTrackElement(int Caller, int HLocInput, int VLocInput, int &ErasedTrackVectorPosition, bool &TrackEraseSuccessfulFlag, bool InternalChecks)
Erases all active and inactive track elements at HLocInput & VLocInput from the vectors,...
Definition: TrackUnit.cpp:1669
TRailGraphics::bmRedEllipse
Graphics::TBitmap * bmRedEllipse
Definition: GraphicUnit.h:525
TRailGraphics::LinkRouteAutoSigsGraphicsPtr
Graphics::TBitmap * LinkRouteAutoSigsGraphicsPtr[30]
auto signal route graphic overlay
Definition: GraphicUnit.h:1012
TRailGraphics::bmDiagonalSignalBlank
Graphics::TBitmap * bmDiagonalSignalBlank
Definition: GraphicUnit.h:983
TRailGraphics::gl83
Graphics::TBitmap * gl83
Definition: GraphicUnit.h:694
FootCrossing
@ FootCrossing
Definition: TrackUnit.h:63
TRailGraphics::sm50
Graphics::TBitmap * sm50
Definition: GraphicUnit.h:817
TRailGraphics::gl25
Graphics::TBitmap * gl25
Definition: GraphicUnit.h:626
TTrack::IsLCAtHV
bool IsLCAtHV(int Caller, int HLoc, int VLoc)
True if a level crossing is found at H & V.
Definition: TrackUnit.cpp:6254
Platform
@ Platform
Definition: TrackUnit.h:63
TOnePrefDir::SearchVector
TPrefDirVector SearchVector
pref dir vectors, first is the main vector, second used to store search elements temporarily
Definition: TrackUnit.h:1233
TPrefDirElement::EXGraphicPtr
Graphics::TBitmap * EXGraphicPtr
Definition: TrackUnit.h:222
TTrack::TGapMapEntry
std::pair< THVPair, THVPair > TGapMapEntry
Definition: TrackUnit.h:576
TRailGraphics::sm95
Graphics::TBitmap * sm95
Definition: GraphicUnit.h:862
TTrack::LevelCrossingBarrierDownFlashDuration
float LevelCrossingBarrierDownFlashDuration
duration of the flash period when level crossing opening
Definition: TrackUnit.h:663
TTrainController::TTClockTime
TDateTime TTClockTime
the time indicated by the timetable clock
Definition: TrainUnit.h:633
TTrack::LocationsNotNamed
bool LocationsNotNamed(int Caller)
True if there are unnamed NamedLocationElements (includes footcrossings)
Definition: TrackUnit.cpp:4115
TTrack::RotLeftArray
int RotLeftArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'rotating left' via menu items 'Edit' & 'Rotate left'
Definition: TrackUnit.h:674
TAllRoutes::TLockedRouteClass::LockStartTime
TDateTime LockStartTime
the timetable time at which the route is locked, to start the 2 minute clock
Definition: TrackUnit.h:1494
TRailGraphics::DirectionNonSigRouteGraphicsPtr
Graphics::TBitmap * DirectionNonSigRouteGraphicsPtr[10]
unrestricted route marker arrows
Definition: GraphicUnit.h:1019
TRailGraphics::sm11
Graphics::TBitmap * sm11
Definition: GraphicUnit.h:757
TRailGraphics::sm125
Graphics::TBitmap * sm125
Definition: GraphicUnit.h:913
TTrack::InactiveMapCheck
bool InactiveMapCheck(int Caller, int HLoc, int VLoc, int SpeedTag)
Used to check the validity of footcrossing links.
Definition: TrackUnit.cpp:6882
TRailGraphics::gl6
Graphics::TBitmap * gl6
Definition: GraphicUnit.h:664
TOnePrefDir
The basic preferred direction class, consisting of any number of elements with preferred directions s...
Definition: TrackUnit.h:1177
TRailGraphics::sm23
Graphics::TBitmap * sm23
Definition: GraphicUnit.h:787
TRailGraphics::sm55
Graphics::TBitmap * sm55
Definition: GraphicUnit.h:822
TTrack::NonFootCrossingNamedLocationExists
bool NonFootCrossingNamedLocationExists(int Caller)
True if there is a platform, NamedNonStationLocation or Concourse present in the railway.
Definition: TrackUnit.cpp:8035
TRailGraphics::BridgePrefDirGraphicsPtr
Graphics::TBitmap * BridgePrefDirGraphicsPtr[12]
preferred direction graphic overlay
Definition: GraphicUnit.h:993
TRailGraphics::sm10
Graphics::TBitmap * sm10
Definition: GraphicUnit.h:746
TTrack::FindClosestLinkPosition
int FindClosestLinkPosition(int Caller, int StartTVPosition, int EndTVPosition)
Return the link array position for the element at StartTVPosition that gives the closest link to the ...
Definition: TrackUnit.cpp:9428
TGraphicElement::SetScreenHVSource
void SetScreenHVSource(int Caller, int HPosIn, int VPosIn)
Set HPos, VPos & SourceRect member values from the supplied positions.
Definition: TrackUnit.cpp:1483
TRailGraphics::sm41
Graphics::TBitmap * sm41
Definition: GraphicUnit.h:807
TUtilities::CallLog
std::deque< AnsiString > CallLog
call stack store, saved to the errorlog for diagnostic purposes
Definition: Utilities.h:54
TRailGraphics::gl22
Graphics::TBitmap * gl22
Definition: GraphicUnit.h:623
TOneRoute::TRouteFlashElement::HLoc
int HLoc
Definition: TrackUnit.h:1361
TRailGraphics::bm100
Graphics::TBitmap * bm100
Definition: GraphicUnit.h:347
TTrack::UserGraphicVector
TUserGraphicVector UserGraphicVector
Definition: TrackUnit.h:700
TTrackElement::Length23
int Length23
Definition: TrackUnit.h:146
TRailGraphics::sm134
Graphics::TBitmap * sm134
Definition: GraphicUnit.h:772
TUtilities::LoadFileBool
bool LoadFileBool(std::ifstream &InFile)
loads a bool value from the file
Definition: Utilities.cpp:140
TRailGraphics::gl71
Graphics::TBitmap * gl71
Definition: GraphicUnit.h:677
TOneRoute::TRouteFlashElement::OverlayGraphic
Graphics::TBitmap * OverlayGraphic
displayed alternately during flashing
Definition: TrackUnit.h:1363
TTrack::TActiveLevelCrossing
Definition: TrackUnit.h:526
TRailGraphics::gl92set
Graphics::TBitmap * gl92set
Definition: GraphicUnit.h:708
TTrack::SaveSessionBarriersDownVector
void SaveSessionBarriersDownVector(int Caller, std::ofstream &OutFile)
Save all vector values to the session file.
Definition: TrackUnit.cpp:3202
TRailGraphics::sm102
Graphics::TBitmap * sm102
Definition: GraphicUnit.h:749
TRailGraphics::gl4
Graphics::TBitmap * gl4
Definition: GraphicUnit.h:642
TDisplay::PlotAndAddUserGraphic
void PlotAndAddUserGraphic(int Caller, TUserGraphicItem UserGraphicItem)
Plot user graphic.
Definition: DisplayUnit.cpp:99
TDisplay::PlotSmallOutput
void PlotSmallOutput(int Caller, int HPos, int VPos, Graphics::TBitmap *PlotItem)
Plot small (4x4) graphic PlotItem on the zoomed-out display at HPos & Vpos.
Definition: DisplayUnit.cpp:112
TTrack::Tag96Array
int Tag96Array[28][3]
Definition: TrackUnit.h:497
TRailGraphics::sm15
Graphics::TBitmap * sm15
Definition: GraphicUnit.h:779
TTrack::LCChangeFlag
bool LCChangeFlag
true when LCs changing
Definition: TrackUnit.h:646
TTrack::SelectVectorAt
TTrackElement & SelectVectorAt(int Caller, int At)
A range-checked version of SelectVector.at(At)
Definition: TrackUnit.cpp:9360
TRailGraphics::sm13
Graphics::TBitmap * sm13
Definition: GraphicUnit.h:766
TRailGraphics::sm91
Graphics::TBitmap * sm91
Definition: GraphicUnit.h:858
TRailGraphics::sm59
Graphics::TBitmap * sm59
Definition: GraphicUnit.h:826
TTrackElement::SpeedLimit23
int SpeedLimit23
Element lengths and speed limits, ...01 is for the track with link positions [0] and [1],...
Definition: TrackUnit.h:146
TTrack::TLNPendingListIterator
TLNPendingList::iterator TLNPendingListIterator
naming of linked named location elements
Definition: TrackUnit.h:592
TRailGraphics::sm114
Graphics::TBitmap * sm114
Definition: GraphicUnit.h:904
TPrefDirElement::LogPrefDir
AnsiString LogPrefDir() const
Sends a list of PrefDirElement values to Utilities->CallLog file for debugging purposes.
Definition: TrackUnit.cpp:250
TRailGraphics::gl82
Graphics::TBitmap * gl82
Definition: GraphicUnit.h:693
TTrack::TActiveLevelCrossing::ChangeDuration
float ChangeDuration
duration of the level crossing changing period
Definition: TrackUnit.h:535
TRailGraphics::gl95set
Graphics::TBitmap * gl95set
Definition: GraphicUnit.h:712
TDisplay::DisplayOffsetVHome
static int DisplayOffsetVHome
the vertical offset of the 'Home' display
Definition: DisplayUnit.h:82
TPrefDirElement::operator==
bool operator==(TPrefDirElement RHElement)
equivalence operator
Definition: TrackUnit.cpp:849
TrainUnit.h
TRailGraphics::bm34
Graphics::TBitmap * bm34
Definition: GraphicUnit.h:412
TRailGraphics::gl104
Graphics::TBitmap * gl104
Definition: GraphicUnit.h:566
TFixedTrackPiece::Link
int Link[4]
Track connection link values, max. of 4, unused = -1, top lh diag.=1, top=2, top rh diag....
Definition: TrackUnit.h:86
TOneRoute::SearchForNonPreferredRoute
bool SearchForNonPreferredRoute(int Caller, TTrackElement CurrentTrackElement, int XLinkPos, int RequiredPosition, IDInt ReqPosRouteID)
Called by GetNextNonPreferredRouteElement to carry out the search for linked track,...
Definition: TrackUnit.cpp:14242
TTrack::TLNDone2MultiMapEntry
std::pair< THVPair, int > TLNDone2MultiMapEntry
can be up to 2 entries (platforms) at a single location
Definition: TrackUnit.h:599
TTrack::TrackMap
TTrackMap TrackMap
map of track (see type for more information above)
Definition: TrackUnit.h:703
RouteCall
@ RouteCall
Definition: TrackUnit.h:1170
TRailGraphics::bm141
Graphics::TBitmap * bm141
Definition: GraphicUnit.h:387
TOnePrefDir::GetFixedSearchElementAt
const TPrefDirElement & GetFixedSearchElementAt(int Caller, int At) const
Return a non-modifiable element at SearchVector position 'At'.
Definition: TrackUnit.cpp:9751
TRailGraphics::sm76striped
Graphics::TBitmap * sm76striped
Definition: GraphicUnit.h:838
TRailGraphics::gl127
Graphics::TBitmap * gl127
Definition: GraphicUnit.h:591
TRailGraphics::bm75yellow
Graphics::TBitmap * bm75yellow
Definition: GraphicUnit.h:501
NotSet
@ NotSet
Definition: TrackUnit.h:72
TTrack::TInactiveTrack2MultiMapIterator
TInactiveTrack2MultiMap::iterator TInactiveTrack2MultiMapIterator
concourses, non-station named locations & parapets)
Definition: TrackUnit.h:580
TAllRoutes::GetAllRoutesTruncateElement
bool GetAllRoutesTruncateElement(int Caller, int HLoc, int VLoc, bool ConsecSignalsRoute)
Examines all routes and for each uses GetRouteTruncateElement to see if the element at H & V is prese...
Definition: TrackUnit.cpp:15558
TAllRoutes::SetTrailingSignalsOnContinuationRoute
void SetTrailingSignalsOnContinuationRoute(int Caller, int RouteNumber, int AccessNumber)
This is called by the InterfaceUnit at intervals based on entries in the ContinuationAutoSigVector in...
Definition: TrackUnit.cpp:16565
TDisplay::DisplayZoomOutOffsetHHome
static int DisplayZoomOutOffsetHHome
the horizontal offset of the zoomed-out 'Home' display
Definition: DisplayUnit.h:88
TMapComp::operator()
bool operator()(const THVPair &lower, const THVPair &higher) const
HLoc VLoc.
Definition: TrackUnit.cpp:212
TRailGraphics::bm16
Graphics::TBitmap * bm16
Definition: GraphicUnit.h:390
TRailGraphics::gl128
Graphics::TBitmap * gl128
Definition: GraphicUnit.h:592
TRailGraphics::gl116
Graphics::TBitmap * gl116
Definition: GraphicUnit.h:579
TTrack::FindHighestLowestAndLeftmostNamedElements
bool FindHighestLowestAndLeftmostNamedElements(int Caller, AnsiString Name, int &VPosHi, int &VPosLo, int &HPos)
Used in locating the screen name position for a named location, return true if find an inactive eleme...
Definition: TrackUnit.cpp:9389
TTrack::TrackClear
void TrackClear(int Caller)
Empty the track and inactive track vectors, the corresponding track maps, and LocationNameMultiMap.
Definition: TrackUnit.cpp:8725
TTrack::TIMPair
std::pair< unsigned int, unsigned int > TIMPair
TrackElement pair type used for inactive elements, values are vector positions.
Definition: TrackUnit.h:587
TTextHandler::TextVectorSize
unsigned int TextVectorSize(int Caller)
return the number of items in TextVector
Definition: TextUnit.cpp:499
TPrefDirElement::ELink
int ELink
Definition: TrackUnit.h:212
TRailGraphics::sm130striped
Graphics::TBitmap * sm130striped
Definition: GraphicUnit.h:768
TRailGraphics::sm118
Graphics::TBitmap * sm118
Definition: GraphicUnit.h:906
TTrack::SetLinkedLevelCrossingBarrierAttributes
void SetLinkedLevelCrossingBarrierAttributes(int Caller, int HLoc, int VLoc, int Attr)
Set linked LC attributes; 0=closed to trains, 1 = open to trains, 2 = changing state = closed to trai...
Definition: TrackUnit.cpp:5569
TTrackElement::GroundSignal
@ GroundSignal
Definition: TrackUnit.h:155
LevelCrossing
@ LevelCrossing
Definition: TrackUnit.h:67
TRailGraphics::sm126
Graphics::TBitmap * sm126
Definition: GraphicUnit.h:914
TRailGraphics::smTransparent
Graphics::TBitmap * smTransparent
Definition: GraphicUnit.h:880
TTrack::ActiveTrackElementNameMapCompiledFlag
bool ActiveTrackElementNameMapCompiledFlag
indicates that the ActiveTrackElementNameMap has been compiled
Definition: TrackUnit.h:640
TOnePrefDir::GetModifiableSearchElementAt
TPrefDirElement & GetModifiableSearchElementAt(int Caller, int At)
Return a modifiable element at SearchVector position 'At'.
Definition: TrackUnit.cpp:9763
TOnePrefDir::TotalSearchCount
int TotalSearchCount
counts search elements, used to abort searches (prefdirs or routes) if reaches too high a value
Definition: TrackUnit.h:1230
Track
TTrack * Track
the object pointer, object created in InterfaceUnit
Definition: TrackUnit.cpp:52
TRailGraphics::bm18
Graphics::TBitmap * bm18
Definition: GraphicUnit.h:391
TTrackElement::Conn
int Conn[4]
Connecting element position in TrackVector, set to -1 if no connecting link or if track not linked.
Definition: TrackUnit.h:140
TTrack::~TTrack
~TTrack()
Destructor.
Definition: TrackUnit.cpp:1242
TRailGraphics::sm62
Graphics::TBitmap * sm62
Definition: GraphicUnit.h:830
TRailGraphics::LCBothVer
Graphics::TBitmap * LCBothVer
Definition: GraphicUnit.h:721
TRailGraphics::sm35
Graphics::TBitmap * sm35
Definition: GraphicUnit.h:800
RailGraphics
TRailGraphics * RailGraphics
the object pointer, object created in InterfaceUnit
Definition: GraphicUnit.cpp:49
TRailGraphics::gl81
Graphics::TBitmap * gl81
Definition: GraphicUnit.h:692
TTrack::HLocMax
int HLocMax
Definition: TrackUnit.h:486
TRailGraphics::gl146
Graphics::TBitmap * gl146
Definition: GraphicUnit.h:614
TTrack::PlotSmallRedGap
void PlotSmallRedGap(int Caller)
Plot on screen in zoomed-out mode and in gap setting mode a small red square corresponding to the gap...
Definition: TrackUnit.cpp:8716
Bridge
@ Bridge
Definition: TrackUnit.h:63
TRailGraphics::sm78
Graphics::TBitmap * sm78
Definition: GraphicUnit.h:841
TRailGraphics::bm43
Graphics::TBitmap * bm43
Definition: GraphicUnit.h:439
InRouteFalse
@ InRouteFalse
Definition: TrackUnit.h:1164
TRailGraphics::sm25
Graphics::TBitmap * sm25
Definition: GraphicUnit.h:789
TRailGraphics::bmName
Graphics::TBitmap * bmName
Definition: GraphicUnit.h:523
Gap
@ Gap
Definition: TrackUnit.h:72
Buffers
@ Buffers
Definition: TrackUnit.h:63
TOneRoute::SetRemainingSearchVectorValues
void SetRemainingSearchVectorValues(int Caller)
Called when setting unrestricted routes to set the route element values appropriately after a success...
Definition: TrackUnit.cpp:14548
TRailGraphics::gl79Striped
Graphics::TBitmap * gl79Striped
Definition: GraphicUnit.h:689
TUtilities::ScreenElementHeight
int ScreenElementHeight
height of display screen in elements
Definition: Utilities.h:49
CrossConn
@ CrossConn
Definition: TrackUnit.h:72
TOnePrefDir::GetPrefDirStartElement
bool GetPrefDirStartElement(int Caller, int HLoc, int VLoc)
Used when beginning a chain of preferred directions or element lengths. Enter with HLoc & VLoc set to...
Definition: TrackUnit.cpp:9775
TOneRoute::GetNextNonPreferredRouteElement
bool GetNextNonPreferredRouteElement(int Caller, int HLoc, int VLoc, bool ConsecSignalsRoute, bool Callon, IDInt &ReqPosRouteID, bool &PointsChanged)
Try to find a set of linked tracks between the route start element and the one at HLoc & VLoc....
Definition: TrackUnit.cpp:13886
TRailGraphics::bm71grounddblwhite
Graphics::TBitmap * bm71grounddblwhite
Definition: GraphicUnit.h:473
TTrack::GapsUnset
bool GapsUnset(int Caller)
True if there are gaps in the railway and any are unset.
Definition: TrackUnit.cpp:4028
TOnePrefDir::LastElementNumber
int LastElementNumber(int Caller) const
Return the vector position of the last element in the vector (i.e. one less than the vector size)
Definition: TrackUnit.cpp:9698
TRailGraphics::sm58
Graphics::TBitmap * sm58
Definition: GraphicUnit.h:825